am c339fe30: am be6ab576: Merge "Fix application launch shortcuts." into ics-mr1

* commit 'c339fe302bc5083f0a110569eec06676be511088':
  Fix application launch shortcuts.
diff --git a/api/current.txt b/api/current.txt
index 4cf23eb..86b6d8f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5502,7 +5502,16 @@
     field public static final java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
     field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
     field public static final java.lang.String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE";
+    field public static final java.lang.String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+    field public static final java.lang.String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+    field public static final java.lang.String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+    field public static final java.lang.String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+    field public static final java.lang.String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+    field public static final java.lang.String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+    field public static final java.lang.String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
     field public static final java.lang.String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
+    field public static final java.lang.String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+    field public static final java.lang.String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
     field public static final java.lang.String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
     field public static final java.lang.String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
     field public static final java.lang.String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
@@ -17057,7 +17066,7 @@
     field public static final java.lang.String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
     field public static final java.lang.String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH";
     field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
-    field public static final java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
+    field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
     field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
     field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
     field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia";
@@ -22217,6 +22226,8 @@
     field public static final int KEYCODE_BUTTON_Y = 100; // 0x64
     field public static final int KEYCODE_BUTTON_Z = 101; // 0x65
     field public static final int KEYCODE_C = 31; // 0x1f
+    field public static final int KEYCODE_CALCULATOR = 210; // 0xd2
+    field public static final int KEYCODE_CALENDAR = 208; // 0xd0
     field public static final int KEYCODE_CALL = 5; // 0x5
     field public static final int KEYCODE_CAMERA = 27; // 0x1b
     field public static final int KEYCODE_CAPS_LOCK = 115; // 0x73
@@ -22225,6 +22236,7 @@
     field public static final int KEYCODE_CHANNEL_UP = 166; // 0xa6
     field public static final int KEYCODE_CLEAR = 28; // 0x1c
     field public static final int KEYCODE_COMMA = 55; // 0x37
+    field public static final int KEYCODE_CONTACTS = 207; // 0xcf
     field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
     field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
     field public static final int KEYCODE_D = 32; // 0x20
@@ -22292,6 +22304,7 @@
     field public static final int KEYCODE_MINUS = 69; // 0x45
     field public static final int KEYCODE_MOVE_END = 123; // 0x7b
     field public static final int KEYCODE_MOVE_HOME = 122; // 0x7a
+    field public static final int KEYCODE_MUSIC = 209; // 0xd1
     field public static final int KEYCODE_MUTE = 91; // 0x5b
     field public static final int KEYCODE_N = 42; // 0x2a
     field public static final int KEYCODE_NOTIFICATION = 83; // 0x53
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 45a42e4..9948985 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2310,6 +2310,74 @@
 
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
+    // Application launch intent categories (see addCategory()).
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the browser application.
+     * The activity should be able to browse the Internet.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the calculator application.
+     * The activity should be able to perform standard arithmetic operations.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the calendar application.
+     * The activity should be able to view and manipulate calendar entries.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the contacts application.
+     * The activity should be able to view and manipulate address book entries.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the email application.
+     * The activity should be able to send and receive email.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the gallery application.
+     * The activity should be able to view and manipulate image and video files
+     * stored on the device.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the maps application.
+     * The activity should be able to show the user's current location and surroundings.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the messaging application.
+     * The activity should be able to send and receive text messages.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the music application.
+     * The activity should be able to play, browse, or manipulate music files stored on the device.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
+
+    // ---------------------------------------------------------------------
+    // ---------------------------------------------------------------------
     // Standard extra data keys.
 
     /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 5f111eb..4e01672 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -40,8 +40,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.Collator;
 
 /**
  * The Media provider contains meta data for all available media on both internal
@@ -66,7 +64,10 @@
     /**
      * Activity Action: Launch a music player.
      * The activity should be able to play, browse, or manipulate music files stored on the device.
+     *
+     * @deprecated Use {@link android.content.Intent#CATEGORY_APP_MUSIC} instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
 
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6c3d387..f53e42c 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -579,8 +579,20 @@
     /** Key code constant: 3D Mode key.
      * Toggles the display between 2D and 3D mode. */
     public static final int KEYCODE_3D_MODE         = 206;
+    /** Key code constant: Contacts special function key.
+     * Used to launch an address book application. */
+    public static final int KEYCODE_CONTACTS        = 207;
+    /** Key code constant: Calendar special function key.
+     * Used to launch a calendar application. */
+    public static final int KEYCODE_CALENDAR        = 208;
+    /** Key code constant: Music special function key.
+     * Used to launch a music player application. */
+    public static final int KEYCODE_MUSIC           = 209;
+    /** Key code constant: Calculator special function key.
+     * Used to launch a calculator application. */
+    public static final int KEYCODE_CALCULATOR      = 210;
 
-    private static final int LAST_KEYCODE           = KEYCODE_BUTTON_16;
+    private static final int LAST_KEYCODE           = KEYCODE_CALCULATOR;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -589,6 +601,8 @@
     //  external/webkit/WebKit/android/plugins/ANPKeyCodes.h
     //  frameworks/base/core/res/res/values/attrs.xml
     //  emulator?
+    //  LAST_KEYCODE
+    //  KEYCODE_SYMBOLIC_NAMES
     //
     //  Also Android currently does not reserve code ranges for vendor-
     //  specific key codes.  If you have new key codes to have, you
@@ -807,6 +821,10 @@
         names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH");
         names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE");
         names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE");
+        names.append(KEYCODE_CONTACTS, "KEYCODE_CONTACTS");
+        names.append(KEYCODE_CALENDAR, "KEYCODE_CALENDAR");
+        names.append(KEYCODE_MUSIC, "KEYCODE_MUSIC");
+        names.append(KEYCODE_CALCULATOR, "KEYCODE_CALCULATOR");
     };
 
     // Symbolic names of all metakeys in bit order from least significant to most significant.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d0ab8b1..af59198 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1493,6 +1493,10 @@
         <enum name="KEYCODE_LANGUAGE_SWITCH" value="204" />
         <enum name="KEYCODE_MANNER_MODE" value="205" />
         <enum name="KEYCODE_3D_MODE" value="206" />
+        <enum name="KEYCODE_CONTACTS" value="207" />
+        <enum name="KEYCODE_CALENDAR" value="208" />
+        <enum name="KEYCODE_MUSIC" value="209" />
+        <enum name="KEYCODE_CALCULATOR" value="210" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 10de6ac..fdd9040 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -159,7 +159,7 @@
 # key 137 "KEY_CUT"
 # key 138 "KEY_HELP"
 key 139   MENU              WAKE_DROPPED
-# key 140 "KEY_CALC"
+key 140   CALCULATOR
 # key 141 "KEY_SETUP"
 key 142   POWER             WAKE
 key 143   POWER             WAKE
@@ -190,7 +190,7 @@
 key 168   MEDIA_REWIND
 key 169   CALL
 # key 170 "KEY_ISO"
-# key 171 "KEY_CONFIG"
+key 171   MUSIC
 key 172   HOME
 # key 173 "KEY_REFRESH"
 # key 174 "KEY_EXIT"
@@ -232,7 +232,7 @@
 # key 210 "KEY_PRINT"
 # key 211 "KEY_HP"
 key 212   CAMERA
-# key 213 "KEY_SOUND"
+key 213   MUSIC
 # key 214 "KEY_QUESTION"
 key 215   ENVELOPE
 # key 216 "KEY_CHAT"
@@ -344,7 +344,7 @@
 # key 394 "KEY_DIRECTORY"
 # key 395 "KEY_LIST"
 # key 396 "KEY_MEMO"
-# key 397 "KEY_CALENDAR"
+key 397   CALENDAR
 # key 398 "KEY_RED"
 # key 399 "KEY_GREEN"
 # key 400 "KEY_YELLOW"
@@ -364,6 +364,7 @@
 # key 414 "KEY_TEEN"
 # key 415 "KEY_TWEN"
 
+key 429   CONTACTS
 
 # key 448 "KEY_DEL_EOL"
 # key 449 "KEY_DEL_EOS"
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 2efe8ca..c5bd0c5 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -231,6 +231,10 @@
     { "LANGUAGE_SWITCH", 204 },
     { "MANNER_MODE", 205 },
     { "3D_MODE", 206 },
+    { "CONTACTS", 207 },
+    { "CALENDAR", 208 },
+    { "MUSIC", 209 },
+    { "CALCULATOR", 210 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h
index 5d49775..8414ff6 100644
--- a/native/include/android/keycodes.h
+++ b/native/include/android/keycodes.h
@@ -250,6 +250,10 @@
     AKEYCODE_LANGUAGE_SWITCH = 204,
     AKEYCODE_MANNER_MODE     = 205,
     AKEYCODE_3D_MODE         = 206,
+    AKEYCODE_CONTACTS        = 207,
+    AKEYCODE_CALENDAR        = 208,
+    AKEYCODE_MUSIC           = 209,
+    AKEYCODE_CALCULATOR      = 210,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml
index 83229f4..454f456 100644
--- a/packages/SettingsProvider/res/xml/bookmarks.xml
+++ b/packages/SettingsProvider/res/xml/bookmarks.xml
@@ -19,6 +19,7 @@
      Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here.
 
      Typical shortcuts (not necessarily defined here):
+       'a': Calculator
        'b': Browser
        'c': Contacts
        'e': Email
@@ -32,27 +33,27 @@
 -->
 <bookmarks>
     <bookmark
-        package="com.android.browser"
-        class="com.android.browser.BrowserActivity"
+        category="android.intent.category.APP_CALCULATOR"
+        shortcut="a" />
+    <bookmark
+        category="android.intent.category.APP_BROWSER"
         shortcut="b" />
     <bookmark
-        package="com.android.contacts"
-        class="com.android.contacts.activities.ContactsFrontDoor"
+        category="android.intent.category.APP_CONTACTS"
         shortcut="c" />
     <bookmark
-        package="com.google.android.email"
-        class="com.android.email.activity.Welcome"
+        category="android.intent.category.APP_EMAIL"
         shortcut="e" />
     <bookmark
-        package="com.google.android.calendar"
-        class="com.android.calendar.LaunchActivity"
+        category="android.intent.category.APP_CALENDAR"
         shortcut="l" />
     <bookmark
-        package="com.android.music"
-        class="com.android.music.MusicBrowserActivity"
+        category="android.intent.category.APP_MAPS"
+        shortcut="m" />
+    <bookmark
+        category="android.intent.category.APP_MUSIC"
         shortcut="p" />
     <bookmark
-        package="com.android.mms"
-        class="com.android.mms.ui.ConversationList"
+        category="android.intent.category.APP_MESSAGING"
         shortcut="s" />
 </bookmarks>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index aa08e64..080d345 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 70;
+    private static final int DATABASE_VERSION = 71;
 
     private Context mContext;
 
@@ -946,6 +946,12 @@
             upgradeVersion = 70;
         }
 
+        if (upgradeVersion == 70) {
+            // Update all built-in bookmarks.  Some of the package names have changed.
+            loadBookmarks(db);
+            upgradeVersion = 71;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1086,16 +1092,11 @@
      * Loads the default set of bookmarked shortcuts from an xml file.
      *
      * @param db The database to write the values into
-     * @param startingIndex The zero-based position at which bookmarks in this file should begin
      */
-    private int loadBookmarks(SQLiteDatabase db, int startingIndex) {
-        Intent intent = new Intent(Intent.ACTION_MAIN, null);
-        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+    private void loadBookmarks(SQLiteDatabase db) {
         ContentValues values = new ContentValues();
 
         PackageManager packageManager = mContext.getPackageManager();
-        int i = startingIndex;
-
         try {
             XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
             XmlUtils.beginDocument(parser, "bookmarks");
@@ -1118,54 +1119,60 @@
                 String pkg = parser.getAttributeValue(null, "package");
                 String cls = parser.getAttributeValue(null, "class");
                 String shortcutStr = parser.getAttributeValue(null, "shortcut");
+                String category = parser.getAttributeValue(null, "category");
 
                 int shortcutValue = shortcutStr.charAt(0);
                 if (TextUtils.isEmpty(shortcutStr)) {
                     Log.w(TAG, "Unable to get shortcut for: " + pkg + "/" + cls);
+                    continue;
                 }
 
-                ActivityInfo info = null;                
-                ComponentName cn = new ComponentName(pkg, cls);
-                try {
-                    info = packageManager.getActivityInfo(cn, 0);
-                } catch (PackageManager.NameNotFoundException e) {
-                    String[] packages = packageManager.canonicalToCurrentPackageNames(
-                            new String[] { pkg });
-                    cn = new ComponentName(packages[0], cls);
+                final Intent intent;
+                final String title;
+                if (pkg != null && cls != null) {
+                    ActivityInfo info = null;
+                    ComponentName cn = new ComponentName(pkg, cls);
                     try {
                         info = packageManager.getActivityInfo(cn, 0);
-                    } catch (PackageManager.NameNotFoundException e1) {
-                        Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                                new String[] { pkg });
+                        cn = new ComponentName(packages[0], cls);
+                        try {
+                            info = packageManager.getActivityInfo(cn, 0);
+                        } catch (PackageManager.NameNotFoundException e1) {
+                            Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
+                            continue;
+                        }
                     }
-                }
-                
-                if (info != null) {
+
+                    intent = new Intent(Intent.ACTION_MAIN, null);
+                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
                     intent.setComponent(cn);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    values.put(Settings.Bookmarks.INTENT, intent.toUri(0));
-                    values.put(Settings.Bookmarks.TITLE,
-                            info.loadLabel(packageManager).toString());
-                    values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
-                    db.insert("bookmarks", null, values);
-                    i++;
+                    title = info.loadLabel(packageManager).toString();
+                } else if (category != null) {
+                    intent = new Intent(Intent.ACTION_MAIN, null);
+                    intent.addCategory(category);
+                    title = "";
+                } else {
+                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutStr
+                            + ": missing package/class or category attributes");
+                    continue;
                 }
+
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                values.put(Settings.Bookmarks.INTENT, intent.toUri(0));
+                values.put(Settings.Bookmarks.TITLE, title);
+                values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
+                db.delete("bookmarks", "shortcut = ?",
+                        new String[] { Integer.toString(shortcutValue) });
+                db.insert("bookmarks", null, values);
             }
         } catch (XmlPullParserException e) {
             Log.w(TAG, "Got execption parsing bookmarks.", e);
         } catch (IOException e) {
             Log.w(TAG, "Got execption parsing bookmarks.", e);
         }
-
-        return i;
-    }
-
-    /**
-     * Loads the default set of bookmark packages.
-     *
-     * @param db The database to write the values into
-     */
-    private void loadBookmarks(SQLiteDatabase db) {
-        loadBookmarks(db, 0);
     }
 
     /**
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2451322..a3d04c4 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -69,6 +69,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.IWindowManager;
@@ -230,7 +231,30 @@
     // Useful scan codes.
     private static final int SW_LID = 0x00;
     private static final int BTN_MOUSE = 0x110;
-    
+
+    /* Table of Application Launch keys.  Maps from key codes to intent categories.
+     *
+     * These are special keys that are used to launch particular kinds of applications,
+     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
+     * usage page.  We don't support quite that many yet...
+     */
+    static SparseArray<String> sApplicationLaunchKeyCategories;
+    static {
+        sApplicationLaunchKeyCategories = new SparseArray<String>();
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
+    }
+
     /**
      * Lock protecting internal state.  Must not call out into window
      * manager with lock held.  (This lock will be acquired in places
@@ -1649,6 +1673,23 @@
             }
         }
 
+        // Handle application launch keys.
+        if (down && repeatCount == 0) {
+            String category = sApplicationLaunchKeyCategories.get(keyCode);
+            if (category != null) {
+                Intent intent = new Intent(Intent.ACTION_MAIN);
+                intent.addCategory(category);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                try {
+                    mContext.startActivity(intent);
+                } catch (ActivityNotFoundException ex) {
+                    Slog.w(TAG, "Dropping application launch key because "
+                            + "the activity to which it is registered was not found: "
+                            + "keyCode=" + keyCode + ", category=" + category, ex);
+                }
+            }
+        }
+
         return 0;
     }