Hi Facebook

Today is my first day in Facebook London. It has been almost six months since I got the offer, and the wait is finally over.

New job, new country, new life.

Connect 163.com With Javamail

Last week I was working on supporting more IMAP email service provider in our app. 163.com is a popular email service used in China, so we created a test account to play around with it.

We already have code working on various email service like yahoo and outlook, so I expect it should not be any problem to connect 163.com, maybe a few custom handling on simplified Chinese.

However, when I try to make connection to IMAP server, I got

NO SELECT The login is not safe! Please update your mail client: http://mail.163.com/dashi

and the link provided goes to the download page of 163’s official app.

It would be sad if 163 somehow limited the IMAP usage to certain apps but let’s not jump to conclusion so fast. After some research, we found that Gmail android app can actually login to 163 account, and that’s the only one we found so far. Googled around and see others met similar problem and found one interesting (and wtf) workaround.

https://github.com/dinhviethoa/libetpan/pull/190 https://github.com/dinhviethoa/libetpan/commit/050f15f30ce40c02d4cf0a9389baca77dec19230

So what does that workaround do? IMAP command is usually in the format

1 CAPABILITY 
2 LOGIN USERNAME PASSWORD 
3 CAPABILITY 
4 LIST "" "" 
5 ID NIL 
6 SELECT INBOX  

but 163 required a “C” before each command, eg

C1 CAPABILITY

so the fix is… add “C”.

To apply to Javamail, we need to modify the Protocol object’s writeCommand method and use a “C” prefix for 163 (also 126.com, yeah.net) imap host address.

Implement Meme Generator With StaticLayout

Two months ago I started writing a meme generator as a side project, what I want to do is not just adding two lines of text on image but a more generic text-on-image solution.

StaticLayout

When implementing custom views, we can use canvas.drawText to display text, but if you want to draw text in multiple lines, a straight forward way is to calculate the y position of each line and draw them one by one. One problem with this method is that, you have to do the line splitting yourself and it seems lots of work.

StaticLayout is a less well-known class in the framework, it is not included in any API Guides or Training documentation.

This is used by widgets to control text layout. You should not need to use this class directly unless you are implementing your own widget or custom display object, or would be tempted to call Canvas.drawText() directly.

But if you take a quick look of inside TextView (like 5000 lines, I have not read it in detail), you will find that StaticLayout is used to do the text layout.

Meme generator structure

RendererView

A custom view that extends ImageView to provide text on image drawing ability, the actually text drawing logic is implemented in the renderer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class RendererView extends ImageView {
    private Renderer mRenderer;

    // fill in constrcutor

    public void setRenderer(MemeRenderer renderer) {
        mRenderer = renderer;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mRenderer != null) {
            mRenderer.draw(canvas);
        }

    }
}

TextGroup

A basic TextGroup manages the text, Paint and StaticLayout object.

To draw text with stroke, we need to draw it twice, first draw the stroke (using Paint.Style.STROKE), then draw the text over it. I use a wrapper TextGroup interface to wrap the text and the stroke layout, and can extend to arbitrary number of text layer.

Renderer

Renderer implements a draw(canvas) function to draw text on canvas. In the case of meme generator, the renderer contains two TextGroup, top and bottom. In the draw function, we translate to proper position and run the draw function implemented in the TextGroup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public void draw(Canvas canvas) {

    // some calculation

    canvas.save();
    canvas.translate(x, topY);
    mTopGroup.draw(canvas);
    canvas.restore();

    canvas.save();
    canvas.translate(x, bottomY);
    mBottomGroup.draw(canvas);
    canvas.restore();

}

AutoResizer

With the help of StaticLayout, you can get the line count of your current layout and can adjust your text size to provide an auto resize function.

Play store submission

When I tried to upload my meme generator demo to play store, the new review system rejected my submission as some meme may have copyright issue… So I just changed my images to some free stock photo to get pass the review process.

Here is my demo app

Future work

With the structure I have, I suppose it is easy to modify the app to provide different style/layout and create use case other than meme generator. I have few ideas in mind but that may require other data api and image source to make it works.

Reference

Let’s Do It

Have been busy on this last few months, some get through, some didn’t.

This is just the beginning of the real game, stay focus and take this chance!

2014 Review

Not sure what is the best word to describe this year, it was kind of negative, but I grew when getting through this.

Personal Goal

Well let’s start with something positive. I set a few goals when the year start, and some of them are reached.

  • 5M downloads, this was the goal in 2013, delayed a little bit, still happy to make it.
  • Lose some weight. Although it came back –_– I did lose some.
  • This blog. At first I wrote weekly but then starts run out of topics (and time) and became one post per month. Writing helps me organize my thought and keeps me thinking.

Disappointment

I take my work very seriously, it kills me to watch the team wasting time week over week. I spent quite a lot of time to think if it is my problem or not, I tried to give them benefit of the doubt as I was not involved in most decision, I tried not to blame people on not good at their job because we are a team. However, as I think deeper, I always came to the darker conclusions.

Are we really a team?

Moving on

Making the decision is easy, the hard part is to handle it right. Turned out I was thinking too much, this year could be a bit different if I just trust my guts, but I learned a lot in the process. I would not say it is a waste of time, even though we did spend time for nothing for months. The more time you lost, the more you willing to make it right, and that’s the power to moving on.

Your life is like a start up when you work in one, you move fast, you take risks. 2013 was a new start, 2014 was a process, 2015 is a whole new start.