27 Jun 2010

This day

Last month I was talking to my director at work, and I told him how much I hated Hyderabad and how badly I wanted to leave the city for good.  He said, among other things, that only when things are not going well at work the city gets to you and you want to move out.  That hit me hard, and I started thinking about it.

Now I should say I am really happy with my work as such, and my life in general.  Last night I was sleepy by 9.30pm but suddenly got some idea and sat down to build something that a friend of mine can use in her blog.  That made me sit till midnight or so.  Woke up early this morning.  Tweaked the code I had written last night; spoke to the friend; got some feedback; planned something big for what we were doing.

Then randomly I decided to go to office.  Went to office; helped another friend in his project; did some office work too while I was at it; went out to meet some friends; spent some time out; and now I am home, typing this.  Surprisingly, I was calm and driving responsibly on the road.  My blood pressure didn't rise when the car before me was just too slow.  I didn't cut anyone off in my urge to go past everyone.  I didn't swear much.  When people cut me off I did get irritated, but I didn't go mad like I do nowadays.

Life is suddenly good.

21 Jun 2010

Android tips

I see that many Android users have difficulty in discovering features that are available in their devices.  In this post I am going to share some commonly unknown features/functionality of Android software.
  1. This is a question I have been asked several times by my friends who use Android.  How would you delete or forward a single message in an SMS conversation?  Long press is the answer.  Long press the message you want to delete or forward and you will get a menu that will let you do it.
  2. Android's built-in SMS app will not autocomplete phone numbers of your contacts that are not marked as "mobile".  Not everyone has correctly categorized phone numbers in their contact list, and it could be a pain.  There are two ways to solve it: 1. correctly classify mobile phone numbers as mobile numbers in your contact list; this can be hard to do.  2. Use a third-party app like Handcent SMS for messaging.  Handcent SMS lets you configure if you want to see non-mobile numbers while composing SMS.
  3. Let's say you have a phone without a physical keyboard.  You are in some UI where there is no text entry field, but you want to type something.  For example, imagine you are seeing your contacts list, and you want to find a contact by typing the contact's name.  (It's faster than scrolling and finding it.)  What you can do is long press Menu button, and that will bring the soft keyboard.  Now type the first few letters of the contact to filter the contact list.
  4. You know that all your Google Talk chat history is available in Gmail.  But did you know that you can search your chat log from within Android's Google Talk app itself?  When you are in Google Talk app, press the Search button and enter your search query.  This will show all chats that match your search query.  Opening a result would show you the chat log in the same way Gmail does.  You can even reply to that chat by email or chat from there itself.  This can be extended to other apps too.  Any app's search functionality can be activated by pressing Search key when you are in that app.  You press Search button when in home screen, it brings the regular Google search (or phone search in 2.2/Froyo and above).  You press Search button when in Gmail app, it brings the Gmail search box.
See also: Android tips #2.

    Apple products: why I don't want them?

    I watched the video where Steve Jobs was introducing the "multitasking" feature of iOS.  I think it's a clever way of doing multitasking.  Apple's principle seems to be not providing features for the sake of adding features; but to enhance the functionality of the device.  Also, Apple seems to focus on doing things right, rather than doing things first.

    What do I think of this as a user?  Let's think about one feature: copy-paste.  I agree that copy-paste is not a great experience on Android.  I have never used any iOS device, so I can't compare Android and iOS.  But I am inclined to believe that iOS does it much better than Android.

    Apple took the time to think about how to do copy-paste right, and they introduced it only in version 3 of their OS.  Had I owned a first generation iPhone, not having the ability to copy-paste on my phone would be a severe limitation to me.  Likewise, iOS devices don't do over-the-air syncing yet.  Maybe Apple will implement it in the "right way" at some point, and they might even prove that Android's way of syncing is inferior to what they can do.

    But it all doesn't mean much to me.  I think of myself as an advanced user who can figure things out when something is not working.  Even if it's a little sloppy, I want my features right now; I can't wait for my device manufacturer to think hard and get it Just Right.

    (I have more reasons for not wanting Apple products; this is just one in the list.)

    Running

    Living is running.

    You can run in the streets, smiling at people you see.  You can run in the beaches, listening to the waves.  You can run in the mountains, ascending towards the sky.  And you can also run on a treadmill in an air-conditioned room.

    13 Jun 2010

    Random thoughts: Overcoming addictions

    When we're addicted to something, our addiction can use up (or waste, if you like that word better) a big chunk of our time and money.  On the other hand, addictions are the ones that let us stay sane.  Many people would go crazy if they weren't allowed to do what they were addicted to.

    Getting rid of addictions is not easy.  In fact, it can be one of the hardest things one would accomplish in life.  Let's say I'm trying to overcome my addiction for smoking.  Not smoking is not really the hard part.  Handling the vacuum that results from the 'non-smoking' is relatively very hard.  Addicts have designed their every day around their addiction.  They unconsciously or consciously allocate a portion of their days for their addiction.  When they quit, they have quite a bit of free time with nothing to do.  It's extremely easy to embrace their addiction back to fill that void.

    Many people say that you should say positive things and think positive things, and that being positive is good in general.  If I extend that to handling addictions, I can think of an approach.  Rather than saying "I don't want to do that," try saying "I want to do this".  Rather than spending your energy on "I don't want to smoke," focus on something like "I want to paint".  Now you are setting yourself up in a new environment where you have lesser time to smoke.  You're focusing on spending your time creatively.  That should be a lot easier than simply wanting to throw something away without any clue about what would you'd replace it with.

    11 Jun 2010

    The world and me

    I have been saying this to myself for quite some time now.  Must be at least a few years.  Still I have difficulty keeping this in mind.  Very often I forget this and start to worry about unnecessary things.  Now I am going to say that to myself again, loud and clear: the world doesn't revolve around me!

    9 Jun 2010

    Android task killers

    I think, if Android Market was like iPhone App Store, none of the task killer apps would have been allowed in Market.  Here's why.

    As I am writing this, a search for [task killer] in Android Market finds 88 apps.  All these task killers come in different sizes and colours and varieties; yet their primary function is one thing: kill the apps that are running in the background.  One of the first documents one would read when they learn Android development is Application Fundamentals page of Android Developer Guide.  It says:
    [An activity] is stopped if it is completely obscured by another activity. It still retains all state and member information. However, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.
    This means that Android keeps an app in background because the user might switch back to that app in some time.  This work flow would be familiar to you.  You are reading an email in the Gmail app and you receive an SMS.  You open the SMS from the notification bar and reply to it.  When you are done with the SMS you press Back key of your phone and you are back in Gmail, in exactly the place where you left.  You can continue to do what you were doing in Gmail.  To make this possible, Android keeps Gmail app's state in memory.

    Let's say you don't come back to Gmail, but you open a game and start playing.  And let's assume this game needs a lot of memory.  Now Android would kill the Gmail app automatically and reclaim the memory used by Gmail.  It's given to the game you just started.

    Android keeps recent apps in memory that would otherwise be left empty and kills apps and reclaims memory exactly when it is required.  This lets you get back to the state in which you left an app so you can continue whatever you were doing.

    All these task killers do is kill the background apps immediately discounting the possibility that you might want to go back to the same app.  If you are thinking task killers make your phone faster, think again.  They are actually making you slow.

    2 Jun 2010

    Buzz feed widget for your blog

    Google Buzz has a JavaScript API that lets you do several things with Buzz.  What I needed was a widget on my blog that would show my recent Buzz activity.  I spent a few hours and hacked up one myself.  Thought of sharing the code with others. (This code doesn't come with any sort of expressed or implied warranty. You can do with this code whatsoever you like.)

    The widget shows your 6 recent activities on Buzz.  It links to your Google Buzz profile at the bottom.  For each post, it adds a link to the Buzz item and shows number of likes and comments.  This was my feed at the time of posting:

    You can use this form to quickly add the widget to your blog:

    Buzz User ID What's my user id?
    Number of activities to show

    For now, I am sharing the code here.  I should build some simple UI where you would specify the parameters like no. of items to show, your Buzz user id, etc. and get the code customized for you automatically.  I should also upload the code to someplace prominent, maybe Google Code.  But I would take some time before I do all this.

    If you are adding this widget to your blog, don't forget to replace all occurrences of BUZZ_USER_ID with your own Buzz user id.  If you want to add this to your Blogger blog, but you are not sure how to do it, About.com has an article showing how to add any such widget to Blogger.  This is all HTML, JavaScript, and CSS.  So, you should be able to toss this code into any blog or web page and it should work.


    If you don't use Blogger, you can use the following code to get the widget on your blog.  (Don't forget to replace all occurrences of BUZZ_USER_ID with your own Buzz user id.)

    <style type="text/css">
    #buzz-widget {
      width: 95%;
      padding: 2px;
    }
    #buzz-header {
      text-align: center;
    }
    #buzz-footer {
      text-align: right;
    }
    #buzz-footer a {
      text-decoration: none;
      font-weight: bold;
    }
    .buzz-feed {
      padding: 0;
      margin: 0;
    }
    .buzz-feed .buzz-entry {
      list-style-type: none;
      text-indent: 3px;
      border-bottom: 1px dotted gray;
      padding: 0.5em 0 0.5em 0;
      background-image: none;
    }
    img.buzz-icon {
      vertical-align: text-bottom;
      width: 16px;
      height: 16px;
    }
    </style>
    
    <div id="buzz-widget">
    <div id="buzz-feed"></div>
    <div id="buzz-footer"><img src="http://goo.gl/TmmA" class="buzz-icon" /> <a href="http://www.google.com/profiles/BUZZ_USER_ID">View all buzz &raquo;</a></div>
    </div>
    <script type="text/javascript">
    function getVerb(verb) {
      verbs = {
        'post': 'Posted',
        'share': 'Shared'
      };
      return verbs[verb] || 'Posted';
    }
    
    function normalizeTitle(title) {
      var MAX_LEN = 30;
      if (title.length > MAX_LEN) {
        return title.substr(0, MAX_LEN - 3) + '...';
      } else {
        return title;
      }
    }
    
    function getAttachmentHtml(attachments) {
      for (var i = 0; i < attachments.length; ++i) {
        var atch = attachments[i];
        if (atch.type == 'photo' || atch.type == 'video') {
          return '<img src="' + atch.links.preview[0].href + '">';
        }
      }
      return '';
    }
    
    function getItemHtml(item) {
      var html = getVerb(item.verbs[0]);
      var linkUrl = '';
      if (item.links.alternate[0]) {
        linkUrl = item.links.alternate[0].href;
        html += ' <a href="' + linkUrl + '">' +
            normalizeTitle(item.title) + '</a>';
      } else {
        html += normalizeTitle(item.title);
      }
      html += ' on ' + item.source.title;
      if (item.object.attachments) {
        var attachmentHtml = getAttachmentHtml(item.object.attachments);
        if (attachmentHtml) {
          if (linkUrl) {
            html += '<br><a href="' + linkUrl + '">' + attachmentHtml + '</a>';
          } else {
            html += '<br>' + attachmentHtml;
          }
        }
      }
      
      var numComments = item.links.replies[0].count;
      if (numComments > 0) {
        html += '<br><img src="http://goo.gl/Y4eU" class="buzz-icon"> ' +
            numComments + (numComments > 1 ? ' comments' : ' comment') + '&nbsp;&nbsp;';
      }
      
      var numLikes = item.links.liked[0].count;
      if (numLikes > 0) {
        if (numComments > 0) {
          html += '&nbsp;&nbsp;'
        } else {
          html += '<br>';
        }
        html += '<img src="http://goo.gl/0l9D" class="buzz-icon"> ' +
            numLikes + (numLikes > 1 ? ' likes' : ' like');
      }
      return html;
    }
    
    function showFeed(response) {
      var entries = [];
      var items = response.data.items;
      for (var i = 0; i < items.length; ++i) {
        entries.push(getItemHtml(items[i]));
      }
      document.getElementById('buzz-feed').innerHTML =
          '<ul class="buzz-feed"><li class="buzz-entry">' +
          entries.join('</li><li class="buzz-entry">') +
          '</ul>';
    }
    </script>
    <script type="text/javascript"
        src="https://www.googleapis.com/buzz/v1/activities/BUZZ_USER_ID/@public?alt=json&max-results=6&callback=showFeed">
    </script>