Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Monday, November 13, 2017

Types of Android Tests

I saw this Reddit discussion on Android testing concepts, which tries to categorize tests into short, medium and long. I don't find that a very useful way to think about different types of tests, so I thought I'd give offer my view.

Two dimensions

I think it's more useful to think of tests in two dimensions

  • Does it run on the JVM or needs a device?
  • Does it test the UI or not?

Depending on the answer to these two questions you get 4 types of tests.

JVM tests

JVM tests are the faster to run since you don't need to deploy to a device (physical or emulator), and should be preferred. Try to structure your app so that the logic is in pure Java classes i.e. does not use the Android framework.

Since we are writing Android apps, it is difficult to test the UI without the Android framework. There are two ways you can do that.

Robolectric

The first way to test the UI on the JVM is Robolectric, which mocks the Android framework. I don't recommend that, because the mocked classes don't necessarily reflect the actual behavior on the Android framework.

Model-View-Presenter (MVP)

The second way is to make your Android classes as logic-free as possible. There are various architecture patterns you can use to achieve that, for an example Model-View-Presenter (MVP). MVP allows you to encapsulate the Android part inside the View (Activity or Fragment) and extract the logic into the Presenter, which does not use any Android framework code. This way, you can test the Presenter on the JVM.

Espresso

After you have tested your logic extensively on the JVM (you may want to aim for 100% test coverage), you should add some UI tests. Think of these as sanity checks, going through the happy path to make sure the app does not crash when you bump up the library version. I use Espresso for UI tests, together with Mockito and MockWebServer to set up a hermetic environment for repeatable tests.

More info

Thursday, May 11, 2017

Why I run a conference

As some of you know, I'm one of the organizers for 360|AnDev. It's a lot of work to run a conference, so why do I do it?

I started the conference because I want an inclusive place for people to learn about Android:

  1. We want it to be welcoming to beginners so that they can plug into the community right away. That's why we have a "Getting Started" track (see our CFP).
  2. We want to encourage first-time speakers, so we run Q&A Hangouts to answer as many questions as we can.
  3. We want people to speak regardless of their financial situation, which is why we cover the travel costs for speakers if their companies do not.
  4. We have inclusivity scholarships to help people who cannot otherwise attend.

We did not collect attendee statistics last year, but you can see from our speaker lineup that we were off to a good start in terms of inclusivity.

We need your help

Last year we managed to break even, which was really good for a first-year conference that covers travel costs for speakers. We hope to keep it up, to have a financially viable event that we can run again and again. But we need your help:

  1. Please spread the word. Tell everyone about the event:
    July 13 - 14, 2017. Denver Colorado. 360andev.com.
  2. If you plan to attend, please buy a ticket right away so us organizers are not sitting at the edge our seats wondering if anyone would come.
  3. If you are at a company, please ask your employer if they would like to sponsor the conference: 360andev.com/sponsorship.
  4. Support us via Patreon: https://www.patreon.com/360andev

Every bit helps. Thank you for your support!

Sunday, April 16, 2017

Droidcon Boston Keynote

I just came back from the inaugural edition of Droidcon Boston last week, at the beautiful Calderwood Pavilion.

Keynote preparation

I had the honor to deliver the Day 2 keynote at Droidcon Boston.

I prepared extensively when I first gave this keynote at Android Summit, so this time I was relatively chill about it. I updated some of the slides, and gave a practice version at Denver Droids. For a last minute refresher, I brought the video recording on my laptop and watched myself give the talk on my flight to Boston.

Fresh material

Normally I do not tweak my talk the day before the conference, but after seeing the shout-outs in Annyce's opening keynote I was inspired to do the same.

My talk is about how sharing makes you an expert, and I used tweets from day 1 of the conference as examples.

Learn from each other

That is the beauty of going to a conference: we learn, we share what we learn, and we lift each other up. It was really rewarding to see people getting out of their comfort zone to tweet, blog, sketchnote, and plot to give their very first talk. This is how we build a community.

Watch the keynote

Thursday, March 16, 2017

Lint stuck after upgrading gradle plugin to 2.3.0

app:lint hangs after I upgraded the gradle plugin to 2.3.0.

Unexpected failure during lint analysis (this is a bug in lint or one of the libraries it depends on)

It complains about ProblemReporter.isClassPathCorrect(ProblemReporter.java:4761) and other places in ProblemReporter, but I was not able to pinpoint the problem.

Turns out this is caused by libraries that uses old lint APIs, in my case Timber and Butterknife. Once I updated those dependencies, lint finishes.

Thanks Josh Burton for sharing his solution with me!

Monday, February 13, 2017

Constraint Layout beta5 lint error

Constraint Layout beta 5 is the release candidate, and added a lint to deprecate older versions.

The easiest way to get rid of the lint error is to press Alt-Enter and choose the first option to upgrade.

However, I encountered a bug, which forces me to stay with beta4 until the next version comes out with the fix. I still want to get rid of the lint error so my continuous build does not fail. I didn't want to change lintOptions abortOnError to false in build.gradle because I still want my build to catch other fatal lint errors.

I tried to get Android Studio to fix this lint error for me by choosing Disable inspection from Alt-Enter. Alas, that only changed the local settings. Turns out that I need to go to Settings → Editor → Inspections to undo that.

The option I wanted is Suppress: Add tools:ignore="MissingConstraints" attribute, which modifies the xml for me to add the appropriate lint suppression.

<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:ignore="MissingConstraints">
<!-- Cannot upgrade to beta5 due to http://b.android.com/233863 -->

Finally, I added a comment to remind me why I suppress the lint error.

More info: Suppress Lint Warnings.

Monday, January 16, 2017

Java compatibility in build.gradle

I got an email from Google asking me to update Fit Cat for Android Wear 2.0, so I tried to compile that app after I haven't touched it for a few months.

Since Android Studio evolves so quickly, I wasn't exactly surprised when I got an error:

Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been
compiled using Java 8 or above.

It asked me to add sourceCompatitbility and targetCompatitbility to Java submodules. What does that mean? After a lot of searching plus trial and error I found the answer.

In your top-level build.gradle, add this:

allprojects {
  tasks.withType(JavaCompile) {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
  }
}

Saturday, October 8, 2016

Constraint Layout: Icon Label Text

I am making one of those classic layouts: an icon with two lines of text. I would like to use vector drawable for the icon, and scale it according to the text sizes. I want the top edge of the icon to line up with the top edge of the first line of text, and the bottom edge of the icon to line up with the bottom edge of the second line.

How would I do that? With ConstraintLayout!

<ImageView
  android:id="@+id/flower_image"
  android:layout_width="0dp"
  android:layout_height="0dp"
  app:layout_constraintTop_toTopOf="@+id/label"
  app:layout_constraintBottom_toBottomOf="@+id/text"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintDimensionRatio="1:1"
  app:srcCompat="@drawable/ic_flower"/>
<TextView
  android:id="@+id/label"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:layout_constraintLeft_toRightOf="@+id/image"
  app:layout_constraintTop_toTopOf="parent"
  android:text="@string/flower"
  android:textSize="16sp"/>
<TextView
  android:id="@+id/text"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:layout_constraintTop_toBottomOf="@+id/label"
  app:layout_constraintLeft_toLeftOf="@+id/label"
  android:text="@string/jasmine"
  android:textSize="24sp"/>

The width and the height of the ImageView is 0dp. This tells ConstraintLayout to compute them by the constraints. In this case, the height of the ImageView is determined by these constraints:

app:layout_constraintTop_toTopOf="@+id/label"
app:layout_constraintBottom_toBottomOf="@+id/text"

The width is the same as the height.

app:layout_constraintDimensionRatio="1:1"

The rest of the constraints are for positioning.

With that, the image scales up as the text sizes increase. It stays sharp because it is a vector.

Layout Editor

I tried to make this layout with the Layout Editor, but could not figure out how to create the constraint app:layout_constraintTop_toTopOf="@+id/label" for the ImageView. I was hovering my cursor around the top edge but not sure how to drag it to link the two views. So I added up playing with the editor a bit to deduce the XML attributes, and switched to editing the XML directly. I hope to use the layout editor in my next attempt to use Constraint Layout.

Follow-up Twitter discussion:

Read the whole Twitter thread.

Source code

github.com/chiuki/iconlabeltext

Click on either TextView to increase its size. Click on the image to reset.

Friday, September 16, 2016

TransactionTooLargeException crashes on Nougat

I was testing my app on Android Nougat, and it crashed when I try to move from one Activity to another. I saw this in the log: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 700848 bytes.

Actually, the platform has been printing warning log about this for a while, but let's be honest, who has time to read all the logs? Nougat (API 24) throws TransactionTooLargeExceptions as RuntimeExceptions, so we cannot ignore that any more.

onSaveInstanceState

Turns out I was saving a big list of search results during onSaveInstanceState to persist them over rotation. Time to move that to a Loader!

But what is the limit?

But now I'm curious: What is the limit? I wrote a sample app to find out.

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = new Intent(this, AnotherActivity.class);
    startActivity(intent);
  }

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    int length = 1000;
    Uri uri = getIntent().getData();
    if (uri != null) {
      try {
        length = Integer.parseInt(uri.getLastPathSegment());
      } catch (NumberFormatException e) {
      }
    }

    byte[] data = new byte[length];
    outState.putByteArray("data", data);
  }
}

To try different sizes, I start the app like this:

adb shell am start \
  -a android.intent.action.View \
  -n com.sqisland.tutorial.transcation_too_large/.MainActivity \
  -d 700000

This launches MainActivity, which immediately goes to AnotherActivity. When that happens, the system calls onSaveInstanceState, which tries to stash away a byte array of the length specified in the adb command, retrieved by getIntent().getData(). This way, I can try different numbers without recompiling and redeploying the app.

I did a binary search on a Nougat emulator and my Nexus 9. The limit is slightly different, but it hovers around 500000. That is not a small number, but not too hard to exceed if you try to store data rather than state.

Saturday, June 25, 2016

The State of Android Testing

We all know testing is good for you, but it is very overwhelming. What is a unit test? What is an instrumentation test? Espresso, Robolectric, Mockito… what do all these libraries do? More fundamentally, why should I test?

I'd like to give a keynote talk to answer all these questions. Do you know a conference that would be interested? Perhaps Droidcon NYC?

Friday, March 18, 2016

ClipRect: Draw outside of the box

Do you know how to draw something like this in Android?

Yes, canvas.drawRoundRect()!

radius = height / 2;
rect.set(0, 0, width, height);
canvas.drawRoundRect(rect, radius, radius, paint);

How about something like this?

It kind of looks like the rectangle with rounded corners. If only there is a way to chop off the end! Well, there is: clipRect.

When you clip a canvas, you are telling Android to draw only inside that rectangle. This allows us to color outside of the box, so to speak, but only keep the part that is inside the box. In our case, we will draw a round rect with size width + height by height, but clip it to width by height so the rounded part on the right is "outside".

canvas.save();
canvas.clipRect(0, 0, width, height);

rect.set(0, 0, width + height, height);
canvas.drawRoundRect(rect, radius, radius, paint);

canvas.restore();

Remember to save and restore so the rest of your app can draw wherever it wants.

Challenge

The source code is in ClipRectActivity in android-graphics-demo.

Can you modify it to clip the rectangle on the other side?

Bonus: Try these other techniques!

Thursday, December 31, 2015

Mock Application in Espresso for Dependency Injection

I read this great post by Artem Zinnatullin on How to mock dependencies in Unit, Integration and Functional tests; Dagger, Robolectric and Instrumentation. The part I like the best is to use a different application in tests to provide different dependencies, and I decided to try it with Espresso.

Mock application via custom test runner

My current approach to dependency injection is to expose a setComponent function in my application for tests to supply the test component, which is not great because ideally the application should not have test-specific code.

The new approach is to subclass the application in the androidTest folder and load it during tests via a custom test runner.

public class DemoApplication extends Application {
  private final DemoComponent component = createComponent();

  protected DemoComponent createComponent() {
    return DaggerDemoApplication_ApplicationComponent.builder()
        .clockModule(new ClockModule())
        .build();
  }

  public DemoComponent component() {
    return component;
  }
}

In the application we initialize a DemoComponent with createComponent() and stash it in a final variable to be used later.

public class MockDemoApplication extends DemoApplication {
  @Override
  protected DemoComponent createComponent() {
    return DaggerMainActivityTest_TestComponent.builder()
        .mockClockModule(new MockClockModule())
        .build();
  }
}

For testing, we subclass our application and override createComponent to supply the test component instead.

To use the mock application in tests, we need a custom test runner:

public class MockTestRunner extends AndroidJUnitRunner {
  @Override
  public Application newApplication(
      ClassLoader cl, String className, Context context)
      throws InstantiationException, 
             IllegalAccessException, 
             ClassNotFoundException {
    return super.newApplication(
      cl, MockDemoApplication.class.getName(), context);
  }
}

We give it MockDemoApplication.class.getName() as the class name so the test runner will load the mock application instead of the main one.

Per application vs per test

This approach is slightly different from setComponent because we initialize the test component only once, rather than before each test method. Make sure you clear the state of your test modules before each test so run each test in from a clean slate.

Source code

I have updated two of my repositories to use this approach:

Like this article? Take a look at the outline of my Espresso book and fill in this form to push me to write it! Also check out the published courses: https://gumroad.com/chiuki

Friday, November 27, 2015

Android Dev Summit: Amazing!

Google ran its first Android Dev Summit this November, and I gotta say, it was amazing.

Session Videos

The AV team edited and posted the videos within 2 hours of the talk, so everyone can enjoy the content. My absolute favorite was "Android Studio for Experts". So many tips and tricks!

Check out the playlist for more.

Sketchnotes

I took many sketchnotes during the summit. Here are a few of them:

I will scan them and add the high-resolution version to this PDF when I get home: gum.co/Sketchnotes2015. Download the current edition to get an email when it is updated.

Encore!

Android Dev Summit gave us Android developer lots of in-depth technical content and easy access to the team. I hope Google will do it again!

Friday, November 6, 2015

MVP: The Missing Link

I have been wanting to learn the Model View Presenter pattern for a while, and was super excited to get Michael Cameron to give a talk on it at GDG Boulder last night.

View Interface

I have this vague notion that MVP is good for JUnit testing, and I finally figured out why. The secret, the missing link, is View Interface, which is not a part of the MVP acronym. View Interface defines the contract between the view and the presenter, allowing you to mock one while testing the other.

With View Interface, you can compartmentalize your Android UI code into the view (typically a Fragment or Activity), which communicates with your presenter solely through the View Interface. This separation allows you to mock your View Interface with zero Android code, which means you can test your presenter with JUnit on the JVM.

Mocking via build flavors

Mocking is essential for hermetic testing, but people are often intimated by dependency injection frameworks like Dagger. If you prefer, you can provide mocks to your test using build flavors. An excellent technique!

Mockito

Mockito is a great mocking framework with a fluent API. One very nice feature is mocking via annotations. To use that, annotate the fields you want to mock with @Mock, and initialize them all with MockitoAnnotations.initMocks() in your @Before function.

@Mock
private MyThing myThing;

@Mock
private OtherThing otherThing;

@Before
public void setUp() throws Exception {
  MockitoAnnotations.initMocks(this);
}

This is equivalent to:

private MyThing myThing;
private OtherThing otherThing;

@Before public void setUp() throws Exception {
  myThing = Mockito.mock(MyThing.class);
  otherThing = Mockito.mock(OtherThing.class);
}

Slides: http://www.slideshare.net/DarxVal/model-view-presenter-presentation

Codelab

Google has published the excellent Android Testing Codelab going through an app with the MVP architecture. You can see JUnit and Espresso testing in action, mocks via build flavors, and various other techniques. Go check it out!

Thursday, November 5, 2015

Google Games: Leaderboard + Achievements

I have a weakness in cute things. I often play cute games, telling myself that I do it to "learn about game mechanics". This time, I actually integrated Google Play Games Services due to inspiration from playing!

Alphabear

My latest addiction is Alphabear. You earn bears while playing a word game, which gives you extra powers. They show you the list of bears you have collected:

I want that for Fit Cat! A catalog, if you will, showing all the cats that you have seen. Initially I was going to do the UI and tracking myself, but then I came across Google Games Achievements. Perfect!

Leaderboard

When I started looking into Google Games, I learned about Leaderboards as well, which seems a simpler concept to launch with. I just need to submit the number of steps to Google Games, and everything else is handled for me. Great!

One problem though: Fit Cat is a watch face, and the watch does not have direct internet access. To upload the steps, I transfer the data to the phone using the Wearable Data Layer API and send it to Google Games in a WearableListenerService.

To test that, I needed to pace around the house, because the Data Layer API only syncs when the data changes. If I sit on my chair in front of my computer, the number of steps stays the same, and so I will not get a callback. It was pretty hilarious, me pacing around and rushing back to the computer to check the logs and see if the phone received data.

Placeholder achievements

I was going to publish my game with the leaderboard, but got blocked because Google Games requires at least 5 achievements. This was right before Big Android BBQ, and I did not have a lot of time before flying to Texas. So I added 5 placeholder achievements and made them hidden, and launched.

Actual Achievements

After I launched leaderboard, I wanted to go back to repurpose the hidden achievements to show cats. I want them to be public so that you are motivated to reach a goal level to see a certain cat.

Alas, I cannot switch an achievement from hidden to public once I published them. So I created new achievements for the cats.

While "May appear at 10000 steps" gives people a goal to walk more, "Secret" is just really mean if it is not attainable. I was holding off the launch until I came up with 5 achievements to backfill the placeholders. That took a few days, but I now have some fun ones for people to discover!

Play Games app

The nice thing about integrating with Google Play Games Services is that your game will show up in the Play Games app. Friends can compare achievements with each other, which is really fun.

However, Fit Cat was not showing up, and I was not sure why. Turns out you need to categorize your app as "Game" rather than "Application" on Google Play, so now Fit Cat is a "Sports Game".

Usually you play sports games by tapping your fingers on screen and pretending to be playing sports, but this one you actually play with your feet in real life!

Easy gaming

Google Play Games Services has a lot of built-in UI, making it super easy to add gaming to your app, even for a non-game like Fit Cat. There was a few non-obvious requirements (ahem, minimum 5 achievements), so I'd recommend going through the checklist during planning, not before launch like me.

Overall it's a great enhancement to my app, for very little effort. I hope you like it too!

Saturday, October 24, 2015

Big Android BBQ

Just got back from Big Android BBQ, and it has been super fun!

Korean mall

I arrived the day before the conference to hang out with Virginia Poltrack, my partner on Fit Cat. I needed a pencil case for my Copic markers so we went to the Korean mall in Carrollton.

First stop was H-Mart, where we ate some yummy dumplings and bought Asian fruits and snacks. And then we went to Daiso, my favorite Japanese dollar store.

I found the perfect pencil case! It was actually a water bottle case, but the top-opening zipper let me see the color of all my markers. I love it.

BBQ decor

The Big Android BBQ team did an amazing job on the decor. The keynote stage was a diner set, and there were lots of nice touches everywhere.

Tech talks

To be honest, when I first looked into this conference I was worried that it is more of a party than a technical conference. I decided to go any way, betting on Google Developers to provide a healthy dose of Android on top of the BBQ.

Colt McAnlis opened the conference with a hilarious Texan keynote.

I went to the automatic performance testing codelab, which was really good, albeit the facilitators running it way too fast.

I ended up not going to too many Google sessions because I brought 3 lady speakers from Colorado with me, and they all gave excellent talks!

I also really enjoyed the animation talk by Marie. Love her method of sticky note + stop motion video for prototyping!

Espresso

I gave my Advanced Android Espresso talk towards the end of the last day. It was my second time giving this talk, so I was pretty relaxed about it. But the projector stopped working in the middle of my presentation! I stood on stage not sure what to do, and literally said, "Help!"

The AV technician came to debug, at which point all the plugging and unplugging crashed my laptop. So I asked to borrow a computer from the audience. After a while the projector was finally working, and what did I do? Accidentally close the browser on my loaner laptop, which had the slides preloaded. The conference wifi wasn't connecting, so a friend set up his Android phone as a wifi hotspot.

With all that, I finally resumed my presentation. I think I stayed quite calm during the whole fiasco, but it totally disrupted the flow of my talk. I was very pleased that the talk was recorded though, and the AV team at Google did an amazing job with the editing. I had to watch it 3 times to find the cut point!

Super friendly crowd

I really enjoyed Big Android BBQ. Everyone is so friendly, and there were many fun little details. The sessions vary in technical depth, but caught quite a few good ones. All in all a great event!

Tuesday, October 6, 2015

Espresso: Save and restore state

Do you save and restore state of your activities, fragments and custom views? Do you test them?

One way to test saving and restoring state is to rotate the screen in your Espresso test.

private void rotateScreen() {
  Context context = InstrumentationRegistry.getTargetContext();
  int orientation 
    = context.getResources().getConfiguration().orientation;

  Activity activity = activityRule.getActivity();
  activity.setRequestedOrientation(
      (orientation == Configuration.ORIENTATION_PORTRAIT) ?
          ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : 
          ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

With this helper function, you can write tests like this:

@Test
public void incrementTwiceAndRotateScreen() {
  onView(withId(R.id.count))
      .check(matches(withText("0")));

  onView(withId(R.id.increment_button))
      .perform(click(), click());
  onView(withId(R.id.count))
      .check(matches(withText("2")));

  rotateScreen();

  onView(withId(R.id.count))
      .check(matches(withText("2")));
}

Source code

https://github.com/chiuki/espresso-samples/ under rotate-screen

Like this article? Take a look at the outline of my Espresso book and fill in this form to push me to write it! Also check out the published courses: https://gumroad.com/chiuki

Saturday, October 3, 2015

Live tweet my own talk

My Android Summit keynote refers to many of my blog posts, and I want to provide links for people to read more. I could stuff all the links in the slide deck, but I decided to try something fun: Live tweet my own talk.

Timing

I used Quicktime to record my talk rehearsal, and watch the video with a pencil and note pad to jot down the minute marks that I am on a topic with a relevant blog post.

Buffer

With the timings, I schedule the tweets to using Buffer so they go live as I speak.

Ask people to follow

I put my twitter handle on every slide, and tell people to follow me so they can get the relevant links as I speak. People were really surprised to get notifications for my tweets while I was clearly still on stage busy speaking!

Thursday, September 3, 2015

Droidcon NYC 2015

I was really excited about Droidcon NYC, not only to learn the latest in Android development, but also to hang out with my fellow female developers. With 22% women speakers, it was not difficult to bump into them during the conference. And I loved it.

Android Dialogs

Huyen and I flew in a day early to record for Android Dialogs, and we got a lot of footage to edit. Here is a recap video to thank everyone who helped us, especially Yash who booked a conference room at her office for us.

Espresso

My talk, Advanced Android Espresso, was assigned to a smaller room upstairs. I have to admit I was disappointed when I saw that. However, everything changed when I was actually in the room. It was packed, and people were staying at the back. The energy was way better than the main stage, which can hold all the attendee so by definition will be rather empty during the 4-track sessions. I much prefer to have a full house!

Droidcon NYC talks are 40 minutes each, and I had so much to share on Espresso that I took them all up. At the end of my talk, I said, “I won’t be taking live questions. Please come up to chat off stage.” Afterwards, my friends told me that they were quite impressed that I dared to defy the norm of taking questions after a talk. Hey, it’s my stage, and I get to call the shots :)

Diversity panel

Besides the Espresso talk, I was invited to be on the diversity panel at Droidcon NYC. We got an audience question on how to cope with a misogynist boss. A female panelist replied that sometimes the best thing to do is to walk away, only to be contradicted by a male panelist, who suggested talking to HR.

“Go to HR? That will destroy your career!”, I thought to myself. “Why would he say that? Are we now touting the party line?” I was so shocked that I did not know what to do. Fortunately, Corey jumped on stage and said what I wanted to say: HR is there to protect the company, not the employee.

We had a discussion off stage after the panel, and to my surprise, the men actually did not know the horror stories of women going to HR only to face retaliation! It was so widely circulated in my circle that I assumed everybody knows.

This panel was truly an eye opener.

Sketchnotes

I started sketchnoting in March, and it was been amazing to see the community pick up on it. There were so many of us sketch noting at Droidcon NYC, including a professional who recorded the keynote by Corey Latislaw.

#LetMeExplainYou

One of the speakers had an emergency and could not make it to the conference. The other speakers want him to be there in spirit, so they inserted a meme slide to their deck!

Droidcon is a truly special community. We are fun and helpful, always ready to step up and make things happen. So honored to be a part of it!

Monday, August 24, 2015

Friend Spell with Google Nearby API

Google recently rolled out Nearby API, allowing nearby devices to message to each other. When I saw that, I thought, party game!

Friend Spell

The goal of Friend Spell is to spell different words with the first letters of the names of your friends. In the example, Chris, Amy and Rae spell the word CAR. If you need to spell TAXI but Xavier isn't in the room, you can find any 4 people instead.

Download from Google Play:

play.google.com/store/apps/details?id=com.sqisland.friendspell

Open source

I have decided to open source the game so people can study an end-to-end app, complete with tests.

github.com/chiuki/friendspell

I did not check in my Nearby API and Google Plus credentials though, so you'll have to add your own com.google.android.nearby.messages.API_KEY in AndroidManifest.xml as well as app/google-services.json file. Refer to the Nearby API and Google Plus documentation for more information.

Technologies used in the project:

Droidcon NYC

Please download Friend Spell and try it out, especially if you are attending Droidcon NYC this week. I'd love to see it in action at a conference!

Tuesday, August 18, 2015

Droidcon NYC: 22% women speakers

I meet a lot of my fellow Android developers at conferences, but I don't see too many women at these events, especially on stage. Organizers claim that they try to get more female speakers, but it is too difficult. So I thought, hey, let's get all the female Android devs I know to submit to a single conference, and see what happens.

Get organized

I got this idea in March, and started a Google Doc to co-ordinate the efforts. We picked Droidcon NYC as the conference for everyone to submit, because it is a good location for people from North America and Europe, and we will have a lot of time to rally people. At that point the conference date was not even announced yet! I invited everyone I know, and ask them to add more people. Corey also did a LinkedIn search to expand the list to folks outside of our social circles.

No excuses

When I asked people to submit a talk, there are a few common concerns:

  • I have nothing to talk about
  • No one wants to listen to me
  • I have no money to travel to the conference

Fortunately I have answers to all of them.

Brainstorming Hangouts

To help people come up with talk ideas, we met on Google Hangout to brainstorm. The funny thing is, most people has come up with an idea or two before showing up at the Hangout, so there wasn't much brainstorming going on. The Hangout is mostly a commitment device for people to set aside some time to think about what they can talk about.

Feedback on the proposals

To convince people that they have something important to say, everyone post their talk ideas on the shared Google doc.

We offer feedback on how to make the abstract better, and also comments on talks that we want to hear. For some reason most people believe that no one wants to hear from them, so it is very reassuring to know that others actually want to learn more.

There are ways to get funding

Money is always a concern. A lot of people just assume that they cannot afford to speak at an out-of-town conference, but us speakers know it is not true.

While a lot of conferences don't have the budget to cover the travel expense for all speakers, many do have a little bit of leeway to help those in need. Ask for help if you need it. There are ways to make it work.

In the case of Droidcon, Intel has set up a female developer sponsorship program. Having a source of funding helped tremendously - people don't immediately dismiss the conference as unreachable.

Q&A with the organizers

To address any other concerns, I arranged a Hangout with the Droidcon organizers:

It is much more convincing when the conference organizer tells you that, yes, we want you to speak!

Nagging

A huge part of this process is sending reminders: email blast to remind everyone of the submission deadline, but also nagging people individually until they submit. I think this is the part where most conferences fall short.

Announcing call for proposals to mailing lists is only the first step. Most people assume that they are not the target, and you have to repeatedly tell them that you indeed want them to speak, help them along the way, and remind them to take action.

People are busy, and if you want results, you have to insist.

Results

We have 14 out of 64 female speaker froms at Droidcon NYC, making 21.875%. While I was hoping for 50%, this is a respectable result, especially since I was leading a grassroot effort, not an official one.

Also, one of the keynotes will be by Corey Latislaw, who proposed the keynote as a part of this effort!

Lessons learned

  1. Start early. It takes a lot of time to rally and nurture potential speakers.
  2. Provide mentorship. Be ready to answer questions about everything from topic ideas to how to fund the travels. Mentorship can be from experienced speakers, but peer support is very powerful too.
  3. Offer to help. I was not an organizer, yet just by telling people about the Intel sponsorship I was able to ease the minds of many people who thought they will not have the money to travel to the conference. For organizers, even if you cannot cover everyone, stating that travel assistance is available on a case-by-case basis can go a long way.
  4. Keep at it. Most importantly, follow through! Asking once is not enough. Monitor the whole process to make sure no one drops off. Send reminders. Nag!

Follow-up post for conference organizers: Up the ante.