| Index: chrome/common/extensions/command.cc
 | 
| diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc
 | 
| index fffc55ef29dcd8a33363a4d73bbf5c81206a9616..be46c20be8e43170b935be4b740d23cf593e4573 100644
 | 
| --- a/chrome/common/extensions/command.cc
 | 
| +++ b/chrome/common/extensions/command.cc
 | 
| @@ -29,10 +29,25 @@ static const char kMissing[] = "Missing";
 | 
|  static const char kCommandKeyNotSupported[] =
 | 
|      "Command key is not supported. Note: Ctrl means Command on Mac";
 | 
|  
 | 
| +bool IsNamedCommand(const std::string& command_name) {
 | 
| +  return command_name != values::kPageActionCommandEvent &&
 | 
| +         command_name != values::kBrowserActionCommandEvent &&
 | 
| +         command_name != values::kScriptBadgeCommandEvent;
 | 
| +}
 | 
| +
 | 
| +bool DoesRequireModifier(const std::string& accelerator) {
 | 
| +  return accelerator != values::kKeyMediaNextTrack &&
 | 
| +         accelerator != values::kKeyMediaPlayPause &&
 | 
| +         accelerator != values::kKeyMediaPrevTrack &&
 | 
| +         accelerator != values::kKeyMediaStop;
 | 
| +}
 | 
| +
 | 
|  ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|                            const std::string& platform_key,
 | 
|                            int index,
 | 
| +                          bool should_parse_media_keys,
 | 
|                            string16* error) {
 | 
| +  error->clear();
 | 
|    if (platform_key != values::kKeybindingPlatformWin &&
 | 
|        platform_key != values::kKeybindingPlatformMac &&
 | 
|        platform_key != values::kKeybindingPlatformChromeOs &&
 | 
| @@ -47,7 +62,9 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|  
 | 
|    std::vector<std::string> tokens;
 | 
|    base::SplitString(accelerator, '+', &tokens);
 | 
| -  if (tokens.size() < 2 || tokens.size() > 3) {
 | 
| +  if (tokens.size() == 0 ||
 | 
| +      (tokens.size() == 1 && DoesRequireModifier(accelerator)) ||
 | 
| +      tokens.size() > 3) {
 | 
|      *error = ErrorUtils::FormatErrorMessageUTF16(
 | 
|          errors::kInvalidKeyBinding,
 | 
|          base::IntToString(index),
 | 
| @@ -99,7 +116,11 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|                 tokens[i] == values::kKeyEnd ||
 | 
|                 tokens[i] == values::kKeyPgUp ||
 | 
|                 tokens[i] == values::kKeyPgDwn ||
 | 
| -               tokens[i] == values::kKeyTab) {
 | 
| +               tokens[i] == values::kKeyTab ||
 | 
| +               tokens[i] == values::kKeyMediaNextTrack ||
 | 
| +               tokens[i] == values::kKeyMediaPlayPause ||
 | 
| +               tokens[i] == values::kKeyMediaPrevTrack ||
 | 
| +               tokens[i] == values::kKeyMediaStop) {
 | 
|        if (key != ui::VKEY_UNKNOWN) {
 | 
|          // Multiple key assignments.
 | 
|          key = ui::VKEY_UNKNOWN;
 | 
| @@ -132,6 +153,18 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|          key = ui::VKEY_NEXT;
 | 
|        } else if (tokens[i] == values::kKeyTab) {
 | 
|          key = ui::VKEY_TAB;
 | 
| +      } else if (tokens[i] == values::kKeyMediaNextTrack &&
 | 
| +                 should_parse_media_keys) {
 | 
| +        key = ui::VKEY_MEDIA_NEXT_TRACK;
 | 
| +      } else if (tokens[i] == values::kKeyMediaPlayPause &&
 | 
| +                 should_parse_media_keys) {
 | 
| +        key = ui::VKEY_MEDIA_PLAY_PAUSE;
 | 
| +      } else if (tokens[i] == values::kKeyMediaPrevTrack &&
 | 
| +                 should_parse_media_keys) {
 | 
| +        key = ui::VKEY_MEDIA_PREV_TRACK;
 | 
| +      } else if (tokens[i] == values::kKeyMediaStop &&
 | 
| +                 should_parse_media_keys) {
 | 
| +        key = ui::VKEY_MEDIA_STOP;
 | 
|        } else if (tokens[i].size() == 1 &&
 | 
|                   tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
 | 
|          key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
 | 
| @@ -151,6 +184,7 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|        return ui::Accelerator();
 | 
|      }
 | 
|    }
 | 
| +
 | 
|    bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0;
 | 
|    bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0;
 | 
|    bool alt = (modifiers & ui::EF_ALT_DOWN) != 0;
 | 
| @@ -172,6 +206,19 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
 | 
|      return ui::Accelerator();
 | 
|    }
 | 
|  
 | 
| +  if ((key == ui::VKEY_MEDIA_NEXT_TRACK ||
 | 
| +       key == ui::VKEY_MEDIA_PREV_TRACK ||
 | 
| +       key == ui::VKEY_MEDIA_PLAY_PAUSE ||
 | 
| +       key == ui::VKEY_MEDIA_STOP) &&
 | 
| +      (shift || ctrl || alt || command)) {
 | 
| +    *error = ErrorUtils::FormatErrorMessageUTF16(
 | 
| +        errors::kInvalidKeyBindingMediaKeyWithModifier,
 | 
| +        base::IntToString(index),
 | 
| +        platform_key,
 | 
| +        accelerator);
 | 
| +    return ui::Accelerator();
 | 
| +  }
 | 
| +
 | 
|    return ui::Accelerator(key, modifiers);
 | 
|  }
 | 
|  
 | 
| @@ -214,7 +261,8 @@ Command::Command(const std::string& command_name,
 | 
|      : command_name_(command_name),
 | 
|        description_(description) {
 | 
|    string16 error;
 | 
| -  accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, &error);
 | 
| +  accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0,
 | 
| +                           IsNamedCommand(command_name), &error);
 | 
|  }
 | 
|  
 | 
|  Command::~Command() {}
 | 
| @@ -235,11 +283,12 @@ std::string Command::CommandPlatform() {
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| -ui::Accelerator Command::StringToAccelerator(const std::string& accelerator) {
 | 
| +ui::Accelerator Command::StringToAccelerator(const std::string& accelerator,
 | 
| +                                             const std::string& command_name) {
 | 
|    string16 error;
 | 
| -  Command command;
 | 
|    ui::Accelerator parsed =
 | 
| -      ParseImpl(accelerator, Command::CommandPlatform(), 0, &error);
 | 
| +      ParseImpl(accelerator, Command::CommandPlatform(), 0,
 | 
| +                IsNamedCommand(command_name), &error);
 | 
|    return parsed;
 | 
|  }
 | 
|  
 | 
| @@ -312,6 +361,18 @@ std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) {
 | 
|        case ui::VKEY_TAB:
 | 
|          shortcut += values::kKeyTab;
 | 
|          break;
 | 
| +      case ui::VKEY_MEDIA_NEXT_TRACK:
 | 
| +        shortcut += values::kKeyMediaNextTrack;
 | 
| +        break;
 | 
| +      case ui::VKEY_MEDIA_PLAY_PAUSE:
 | 
| +        shortcut += values::kKeyMediaPlayPause;
 | 
| +        break;
 | 
| +      case ui::VKEY_MEDIA_PREV_TRACK:
 | 
| +        shortcut += values::kKeyMediaPrevTrack;
 | 
| +        break;
 | 
| +      case ui::VKEY_MEDIA_STOP:
 | 
| +        shortcut += values::kKeyMediaStop;
 | 
| +        break;
 | 
|        default:
 | 
|          return "";
 | 
|      }
 | 
| @@ -326,9 +387,7 @@ bool Command::Parse(const base::DictionaryValue* command,
 | 
|    DCHECK(!command_name.empty());
 | 
|  
 | 
|    string16 description;
 | 
| -  if (command_name != values::kPageActionCommandEvent &&
 | 
| -      command_name != values::kBrowserActionCommandEvent &&
 | 
| -      command_name != values::kScriptBadgeCommandEvent) {
 | 
| +  if (IsNamedCommand(command_name)) {
 | 
|      if (!command->GetString(keys::kDescription, &description) ||
 | 
|          description.empty()) {
 | 
|        *error = ErrorUtils::FormatErrorMessageUTF16(
 | 
| @@ -419,13 +478,16 @@ bool Command::Parse(const base::DictionaryValue* command,
 | 
|      if (!iter->second.empty()) {
 | 
|        // Note that we pass iter->first to pretend we are on a platform we're not
 | 
|        // on.
 | 
| -      accelerator = ParseImpl(iter->second, iter->first, index, error);
 | 
| +      accelerator = ParseImpl(iter->second, iter->first, index,
 | 
| +                              IsNamedCommand(command_name), error);
 | 
|        if (accelerator.key_code() == ui::VKEY_UNKNOWN) {
 | 
| -        *error = ErrorUtils::FormatErrorMessageUTF16(
 | 
| -            errors::kInvalidKeyBinding,
 | 
| -            base::IntToString(index),
 | 
| -            iter->first,
 | 
| -            iter->second);
 | 
| +        if (error->empty()) {
 | 
| +          *error = ErrorUtils::FormatErrorMessageUTF16(
 | 
| +              errors::kInvalidKeyBinding,
 | 
| +              base::IntToString(index),
 | 
| +              iter->first,
 | 
| +              iter->second);
 | 
| +        }
 | 
|          return false;
 | 
|        }
 | 
|      }
 | 
| 
 |