summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-21 21:51:43 +0000
committersatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-21 21:51:43 +0000
commitbd141d8f9578d87ebe7198c94186ba2ce2711312 (patch)
tree42aa948a353b49df7d276765b1a7f1d9d1b4f82b /chrome
parentb09df81df72de5476a35431d2b1f3793d48ef4f6 (diff)
downloadchromium_src-bd141d8f9578d87ebe7198c94186ba2ce2711312.zip
chromium_src-bd141d8f9578d87ebe7198c94186ba2ce2711312.tar.gz
chromium_src-bd141d8f9578d87ebe7198c94186ba2ce2711312.tar.bz2
Extend speech input bubble in Mac to display error messages with try-again and cancel buttons.
The SpeechInputBubbleImpl object now lives longer than the actual info bubble window, and allows the caller to create a bubble on screen or update with an error message when needed. When recording speech, the layout of controls are (vertical): - Label ('Speak now') - Icon (Mic or wait) - Button Bar (Horizontal, 1 button, 'Cancel') When showing a message, the layout of controls are (vertical): - Label (message text) - Button Bar (Horizontal, 2 buttons, 'Try Again' and 'Cancel') Also made a small correction to the info bubble's anchor point to get the arrow point at the correct starting point of the given element rect. XIB changes: - Added a 'try again' button and hooked it up to the tryAgainButton outlet in the controller - Moved position of the cancel button for easier editing in interface builder BUG=53598 TEST=manual, unplug mic and start recognition to check error message, and similarly give no speech to check. Review URL: http://codereview.chromium.org/3438002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60112 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/nibs/SpeechInputBubble.xib92
-rw-r--r--chrome/browser/cocoa/speech_input_window_controller.h22
-rw-r--r--chrome/browser/cocoa/speech_input_window_controller.mm124
-rw-r--r--chrome/browser/speech/speech_input_bubble_browsertest.cc55
-rw-r--r--chrome/browser/speech/speech_input_bubble_mac.mm67
-rw-r--r--chrome/browser/speech/speech_recognizer.cc24
-rw-r--r--chrome/chrome_tests.gypi1
7 files changed, 304 insertions, 81 deletions
diff --git a/chrome/app/nibs/SpeechInputBubble.xib b/chrome/app/nibs/SpeechInputBubble.xib
index b939d96..4f2e84b5 100644
--- a/chrome/app/nibs/SpeechInputBubble.xib
+++ b/chrome/app/nibs/SpeechInputBubble.xib
@@ -57,21 +57,41 @@
<int key="NSvFlags">301</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSButton" id="789820196">
+ <object class="NSButton" id="1038338233">
<reference key="NSNextResponder" ref="926910107"/>
<int key="NSvFlags">268</int>
- <string key="NSFrame">{{47, 12}, {96, 32}}</string>
+ <string key="NSFrame">{{14, 12}, {82, 32}}</string>
<reference key="NSSuperview" ref="926910107"/>
<bool key="NSEnabled">YES</bool>
- <object class="NSButtonCell" key="NSCell" id="541512844">
+ <object class="NSButtonCell" key="NSCell" id="84459405">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
- <string key="NSContents">^IDS_CANCEL</string>
+ <string key="NSContents">^IDS_SPEECH_INPUT_TRY_AGAIN</string>
<object class="NSFont" key="NSSupport" id="487155245">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">13</double>
<int key="NSfFlags">1044</int>
</object>
+ <reference key="NSControlView" ref="1038338233"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ <object class="NSButton" id="789820196">
+ <reference key="NSNextResponder" ref="926910107"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{88, 12}, {88, 32}}</string>
+ <reference key="NSSuperview" ref="926910107"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="541512844">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">^IDS_CANCEL</string>
+ <reference key="NSSupport" ref="487155245"/>
<reference key="NSControlView" ref="789820196"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">129</int>
@@ -236,6 +256,22 @@
</object>
<int key="connectionID">837</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">tryAgainButton_</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="1038338233"/>
+ </object>
+ <int key="connectionID">840</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">tryAgain:</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="1038338233"/>
+ </object>
+ <int key="connectionID">841</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -300,6 +336,7 @@
<reference ref="530565492"/>
<reference ref="793691203"/>
<reference ref="789820196"/>
+ <reference ref="1038338233"/>
</object>
<reference key="parent" ref="414427165"/>
</object>
@@ -345,6 +382,20 @@
<reference key="object" ref="541512844"/>
<reference key="parent" ref="789820196"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">838</int>
+ <reference key="object" ref="1038338233"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="84459405"/>
+ </object>
+ <reference key="parent" ref="926910107"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">839</int>
+ <reference key="object" ref="84459405"/>
+ <reference key="parent" ref="1038338233"/>
+ </object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@@ -366,13 +417,15 @@
<string>815.IBPluginDependency</string>
<string>816.IBPluginDependency</string>
<string>825.IBPluginDependency</string>
+ <string>838.IBPluginDependency</string>
+ <string>839.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{452, 1286}, {190, 190}}</string>
+ <string>{{593, 566}, {190, 190}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{452, 1286}, {190, 190}}</string>
+ <string>{{593, 566}, {190, 190}}</string>
<boolean value="NO"/>
<string>{{11, 666}, {480, 270}}</string>
<string>{3.40282e+38, 3.40282e+38}</string>
@@ -384,6 +437,8 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
@@ -402,7 +457,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">837</int>
+ <int key="maxID">841</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -557,8 +612,17 @@
<string key="className">SpeechInputWindowController</string>
<string key="superclassName">BaseBubbleController</string>
<object class="NSMutableDictionary" key="actions">
- <string key="NS.key.0">cancel:</string>
- <string key="NS.object.0">id</string>
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cancel:</string>
+ <string>tryAgain:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ </object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -567,12 +631,14 @@
<string>cancelButton_</string>
<string>iconImage_</string>
<string>instructionLabel_</string>
+ <string>tryAgainButton_</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSButton</string>
<string>NSImageView</string>
<string>NSTextField</string>
+ <string>NSButton</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
@@ -580,6 +646,14 @@
<string key="minorKey">browser/cocoa/speech_input_window_controller.h</string>
</object>
</object>
+ <object class="IBPartialClassDescription">
+ <string key="className">SpeechInputWindowController</string>
+ <string key="superclassName">BaseBubbleController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
</object>
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
<bool key="EncodedWithXMLCoder">YES</bool>
diff --git a/chrome/browser/cocoa/speech_input_window_controller.h b/chrome/browser/cocoa/speech_input_window_controller.h
index 51f6b8d..11000c2 100644
--- a/chrome/browser/cocoa/speech_input_window_controller.h
+++ b/chrome/browser/cocoa/speech_input_window_controller.h
@@ -21,6 +21,7 @@
IBOutlet NSImageView* iconImage_;
IBOutlet NSTextField* instructionLabel_;
IBOutlet NSButton* cancelButton_;
+ IBOutlet NSButton* tryAgainButton_;
}
// Initialize the window. |anchoredAt| is in screen coordinates.
@@ -31,8 +32,25 @@
// Handler for the cancel button.
- (IBAction)cancel:(id)sender;
-// Inform the user that audio recording has ended and recognition is underway.
-- (void)didStartRecognition;
+// Handler for the try again button.
+- (IBAction)tryAgain:(id)sender;
+
+// Updates the UI with data related to the given display mode.
+- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
+ messageText:(const string16&)messageText;
+
+// Makes the speech input bubble visible on screen.
+- (void)show;
+
+// Hides the speech input bubble away from screen. This does NOT release the
+// controller and the window.
+- (void)hide;
+
+// Sets the image to be displayed in the bubble's status ImageView. A future
+// call to updateLayout may change the image.
+// TODO(satish): Clean that up and move it into the platform independent
+// SpeechInputBubbleBase class.
+- (void)setImage:(NSImage*)image;
@end
diff --git a/chrome/browser/cocoa/speech_input_window_controller.mm b/chrome/browser/cocoa/speech_input_window_controller.mm
index c3dae85..6e8e862 100644
--- a/chrome/browser/cocoa/speech_input_window_controller.mm
+++ b/chrome/browser/cocoa/speech_input_window_controller.mm
@@ -4,10 +4,12 @@
#import "speech_input_window_controller.h"
-#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
#include "app/resource_bundle.h"
+#include "base/logging.h"
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
+
#include "chrome/browser/cocoa/info_bubble_view.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -15,7 +17,7 @@
#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
const int kBubbleControlVerticalSpacing = 10; // Space between controls.
-const int kBubbleHorizontalMargin = 15; // Space on either sides of controls.
+const int kBubbleHorizontalMargin = 5; // Space on either sides of controls.
@interface SpeechInputWindowController (Private)
- (NSSize)calculateContentSize;
@@ -28,7 +30,9 @@ const int kBubbleHorizontalMargin = 15; // Space on either sides of controls.
delegate:(SpeechInputBubbleDelegate*)delegate
anchoredAt:(NSPoint)anchoredAt {
anchoredAt.x -= info_bubble::kBubbleArrowXOffset +
+ info_bubble::kBubbleCornerRadius +
info_bubble::kBubbleArrowWidth / 2.0;
+ anchoredAt.y += info_bubble::kBubbleArrowHeight / 2.0;
if ((self = [super initWithWindowNibPath:@"SpeechInputBubble"
parentWindow:parentWindow
anchoredAt:anchoredAt])) {
@@ -43,10 +47,6 @@ const int kBubbleHorizontalMargin = 15; // Space on either sides of controls.
- (void)awakeFromNib {
NSWindow* window = [self window];
[[self bubble] setArrowLocation:info_bubble::kTopLeft];
- NSImage* icon = ResourceBundle::GetSharedInstance().GetNSImageNamed(
- IDR_SPEECH_INPUT_MIC_EMPTY);
- [iconImage_ setImage:icon];
- [iconImage_ setNeedsDisplay:YES];
NSSize newSize = [self calculateContentSize];
[[self bubble] setFrameSize:newSize];
@@ -66,25 +66,35 @@ const int kBubbleHorizontalMargin = 15; // Space on either sides of controls.
delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
}
+- (IBAction)tryAgain:(id)sender {
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN);
+}
+
// Calculate the window dimensions to reflect the sum height and max width of
// all controls, with appropriate spacing between and around them. The returned
// size is in view coordinates.
- (NSSize)calculateContentSize {
[GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
- NSSize size = [cancelButton_ bounds].size;
- int newHeight = size.height + kBubbleControlVerticalSpacing;
- int newWidth = size.width;
-
- NSImage* icon = ResourceBundle::GetSharedInstance().GetNSImageNamed(
- IDR_SPEECH_INPUT_MIC_EMPTY);
- size = [icon size];
- newHeight += size.height + kBubbleControlVerticalSpacing;
- if (newWidth < size.width)
- newWidth = size.width;
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:tryAgainButton_];
+ NSSize cancelSize = [cancelButton_ bounds].size;
+ NSSize tryAgainSize = [tryAgainButton_ bounds].size;
+ int newHeight = cancelSize.height + kBubbleControlVerticalSpacing;
+ int newWidth = cancelSize.width + tryAgainSize.width;
+
+ if (![iconImage_ isHidden]) {
+ NSImage* icon = ResourceBundle::GetSharedInstance().GetNSImageNamed(
+ IDR_SPEECH_INPUT_MIC_EMPTY);
+ NSSize size = [icon size];
+ newHeight += size.height + kBubbleControlVerticalSpacing;
+ if (newWidth < size.width)
+ newWidth = size.width;
+ } else {
+ newHeight += kBubbleControlVerticalSpacing;
+ }
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
instructionLabel_];
- size = [instructionLabel_ bounds].size;
+ NSSize size = [instructionLabel_ bounds].size;
newHeight += size.height;
if (newWidth < size.width)
newWidth = size.width;
@@ -97,33 +107,79 @@ const int kBubbleHorizontalMargin = 15; // Space on either sides of controls.
- (void)layout:(NSSize)size {
int y = kBubbleControlVerticalSpacing;
- NSRect rect = [cancelButton_ bounds];
- rect.origin.x = (size.width - rect.size.width) / 2;
- rect.origin.y = y;
- [cancelButton_ setFrame:rect];
- y += rect.size.height + kBubbleControlVerticalSpacing;
-
- rect = [iconImage_ bounds];
- rect.origin.x = (size.width - rect.size.width) / 2;
- rect.origin.y = y;
- [iconImage_ setFrame:rect];
- y += rect.size.height + kBubbleControlVerticalSpacing;
+ NSRect cancelRect = [cancelButton_ bounds];
+
+ if ([tryAgainButton_ isHidden]) {
+ cancelRect.origin.x = (size.width - NSWidth(cancelRect)) / 2;
+ } else {
+ NSRect tryAgainRect = [tryAgainButton_ bounds];
+ cancelRect.origin.x = (size.width - NSWidth(cancelRect) -
+ NSWidth(tryAgainRect)) / 2;
+ tryAgainRect.origin.x = cancelRect.origin.x + NSWidth(cancelRect);
+ tryAgainRect.origin.y = y;
+ [tryAgainButton_ setFrame:tryAgainRect];
+ }
+ cancelRect.origin.y = y;
+ [cancelButton_ setFrame:cancelRect];
+
+ y += NSHeight(cancelRect) + kBubbleControlVerticalSpacing;
+
+ NSRect rect;
+ if (![iconImage_ isHidden]) {
+ rect = [iconImage_ bounds];
+ rect.origin.x = (size.width - NSWidth(rect)) / 2;
+ rect.origin.y = y;
+ [iconImage_ setFrame:rect];
+ y += rect.size.height + kBubbleControlVerticalSpacing;
+ }
rect = [instructionLabel_ bounds];
- rect.origin.x = (size.width - rect.size.width) / 2;
+ rect.origin.x = (size.width - NSWidth(rect)) / 2;
rect.origin.y = y;
[instructionLabel_ setFrame:rect];
}
-- (void)didStartRecognition {
- NSImage* icon = ResourceBundle::GetSharedInstance().GetNSImageNamed(
- IDR_SPEECH_INPUT_PROCESSING);
- [iconImage_ setImage:icon];
- [iconImage_ setNeedsDisplay:YES];
+- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
+ messageText:(const string16&)messageText {
+ // Get the right set of controls to be visible.
+ if (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE) {
+ [instructionLabel_ setStringValue:base::SysUTF16ToNSString(messageText)];
+ [iconImage_ setHidden:YES];
+ [tryAgainButton_ setHidden:NO];
+ } else {
+ [instructionLabel_ setStringValue:l10n_util::GetNSString(
+ IDS_SPEECH_INPUT_BUBBLE_HEADING)];
+ NSImage* icon = ResourceBundle::GetSharedInstance().GetNSImageNamed(
+ (mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING ?
+ IDR_SPEECH_INPUT_MIC_EMPTY : IDR_SPEECH_INPUT_PROCESSING));
+ [iconImage_ setImage:icon];
+ [iconImage_ setHidden:NO];
+ [iconImage_ setNeedsDisplay:YES];
+ [tryAgainButton_ setHidden:YES];
+ }
+
+ NSSize newSize = [self calculateContentSize];
+ NSRect rect = [[self bubble] frame];
+ rect.origin.y -= newSize.height - rect.size.height;
+ rect.size = newSize;
+ [[self bubble] setFrame:rect];
+ [self layout:newSize];
}
- (void)windowWillClose:(NSNotification*)notification {
delegate_->InfoBubbleFocusChanged();
}
+- (void)show {
+ [self showWindow:nil];
+}
+
+- (void)hide {
+ [[self window] orderOut:nil];
+}
+
+- (void)setImage:(NSImage*)image {
+ [iconImage_ setImage:image];
+}
+
@end // implementation SpeechInputWindowController
diff --git a/chrome/browser/speech/speech_input_bubble_browsertest.cc b/chrome/browser/speech/speech_input_bubble_browsertest.cc
new file mode 100644
index 0000000..fb96593
--- /dev/null
+++ b/chrome/browser/speech/speech_input_bubble_browsertest.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/speech/speech_input_bubble.h"
+#include "chrome/browser/browser.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "gfx/rect.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class SpeechInputBubbleTest : public SpeechInputBubbleDelegate,
+ public InProcessBrowserTest {
+ public:
+ // SpeechInputBubble::Delegate methods.
+ virtual void InfoBubbleButtonClicked(SpeechInputBubble::Button button) {}
+ virtual void InfoBubbleFocusChanged() {}
+
+ protected:
+};
+
+IN_PROC_BROWSER_TEST_F(SpeechInputBubbleTest, CreateAndDestroy) {
+ gfx::Rect element_rect(100, 100, 100, 100);
+ scoped_ptr<SpeechInputBubble> bubble(SpeechInputBubble::Create(
+ browser()->GetSelectedTabContents(), this, element_rect));
+ EXPECT_TRUE(bubble.get());
+}
+
+IN_PROC_BROWSER_TEST_F(SpeechInputBubbleTest, ShowAndDestroy) {
+ gfx::Rect element_rect(100, 100, 100, 100);
+ scoped_ptr<SpeechInputBubble> bubble(SpeechInputBubble::Create(
+ browser()->GetSelectedTabContents(), this, element_rect));
+ EXPECT_TRUE(bubble.get());
+ bubble->Show();
+}
+
+IN_PROC_BROWSER_TEST_F(SpeechInputBubbleTest, ShowAndHide) {
+ gfx::Rect element_rect(100, 100, 100, 100);
+ scoped_ptr<SpeechInputBubble> bubble(SpeechInputBubble::Create(
+ browser()->GetSelectedTabContents(), this, element_rect));
+ EXPECT_TRUE(bubble.get());
+ bubble->Show();
+ bubble->Hide();
+}
+
+IN_PROC_BROWSER_TEST_F(SpeechInputBubbleTest, ShowAndHideTwice) {
+ gfx::Rect element_rect(100, 100, 100, 100);
+ scoped_ptr<SpeechInputBubble> bubble(SpeechInputBubble::Create(
+ browser()->GetSelectedTabContents(), this, element_rect));
+ EXPECT_TRUE(bubble.get());
+ bubble->Show();
+ bubble->Hide();
+ bubble->Show();
+ bubble->Hide();
+}
diff --git a/chrome/browser/speech/speech_input_bubble_mac.mm b/chrome/browser/speech/speech_input_bubble_mac.mm
index f22db5f..a48eac6 100644
--- a/chrome/browser/speech/speech_input_bubble_mac.mm
+++ b/chrome/browser/speech/speech_input_bubble_mac.mm
@@ -10,6 +10,7 @@
#import "chrome/browser/cocoa/speech_input_window_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "skia/ext/skia_utils_mac.h"
namespace {
@@ -29,51 +30,69 @@ class SpeechInputBubbleImpl : public SpeechInputBubbleBase {
private:
scoped_nsobject<SpeechInputWindowController> window_;
+ TabContents* tab_contents_;
+ Delegate* delegate_;
+ gfx::Rect element_rect_;
};
SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents,
Delegate* delegate,
- const gfx::Rect& element_rect) {
+ const gfx::Rect& element_rect)
+ : tab_contents_(tab_contents),
+ delegate_(delegate),
+ element_rect_(element_rect) {
+}
+
+SpeechInputBubbleImpl::~SpeechInputBubbleImpl() {
+ if (window_.get())
+ [window_.get() close];
+}
+
+void SpeechInputBubbleImpl::SetImage(const SkBitmap& image) {
+ if (window_.get())
+ [window_.get() setImage:gfx::SkBitmapToNSImage(image)];
+}
+
+void SpeechInputBubbleImpl::Show() {
+ if (window_.get()) {
+ [window_.get() show];
+ return;
+ }
+
// Find the screen coordinates for the given tab and position the bubble's
// arrow anchor point inside that to point at the bottom-left of the html
// input element rect.
- gfx::NativeView view = tab_contents->view()->GetNativeView();
+ gfx::NativeView view = tab_contents_->view()->GetNativeView();
NSRect tab_bounds = [view bounds];
NSPoint anchor = NSMakePoint(
- tab_bounds.origin.x + element_rect.x() + kBubbleTargetOffsetX,
- tab_bounds.origin.y + tab_bounds.size.height - element_rect.y() -
- element_rect.height());
+ tab_bounds.origin.x + element_rect_.x() + kBubbleTargetOffsetX,
+ tab_bounds.origin.y + tab_bounds.size.height - element_rect_.y() -
+ element_rect_.height());
anchor = [view convertPoint:anchor toView:nil];
anchor = [[view window] convertBaseToScreen:anchor];
window_.reset([[SpeechInputWindowController alloc]
- initWithParentWindow:tab_contents->view()->GetTopLevelNativeWindow()
- delegate:delegate
+ initWithParentWindow:tab_contents_->view()->GetTopLevelNativeWindow()
+ delegate:delegate_
anchoredAt:anchor]);
-}
-SpeechInputBubbleImpl::~SpeechInputBubbleImpl() {
- [window_.get() close];
-}
-
-void SpeechInputBubbleImpl::SetImage(const SkBitmap& image) {
- // TODO(satish): Implement.
- NOTREACHED();
-}
-
-void SpeechInputBubbleImpl::Show() {
- // TODO(satish): Implement.
- NOTREACHED();
+ UpdateLayout();
}
void SpeechInputBubbleImpl::Hide() {
- // TODO(satish): Implement.
- NOTREACHED();
+ if (!window_.get())
+ return;
+
+ [window_.get() close];
+ window_.reset();
}
void SpeechInputBubbleImpl::UpdateLayout() {
- // TODO(satish): Implement.
- NOTREACHED();
+ if (!window_.get())
+ return;
+
+ [window_.get() updateLayout:display_mode()
+ messageText:message_text()];
}
} // namespace
diff --git a/chrome/browser/speech/speech_recognizer.cc b/chrome/browser/speech/speech_recognizer.cc
index 6eed2f5..ce1bfaa 100644
--- a/chrome/browser/speech/speech_recognizer.cc
+++ b/chrome/browser/speech/speech_recognizer.cc
@@ -31,11 +31,11 @@ COMPILE_ASSERT(kMaxSpeexFrameLength <= 0xFF, invalidLength);
// The following constants are related to the volume level indicator shown in
// the UI for recorded audio.
// Multiplier used when new volume is greater than previous level.
-const float kUpSmoothingFactor = 0.9f;
-// Multiplier used when new volume is lesser than previous level.
-const float kDownSmoothingFactor = 0.4f;
-const float kAudioMeterMinDb = 10.0f; // Lower bar for volume meter.
-const float kAudioMeterDbRange = 25.0f;
+const float kUpSmoothingFactor = 0.9f;
+// Multiplier used when new volume is lesser than previous level.
+const float kDownSmoothingFactor = 0.4f;
+const float kAudioMeterMinDb = 10.0f; // Lower bar for volume meter.
+const float kAudioMeterDbRange = 25.0f;
} // namespace
namespace speech_input {
@@ -293,13 +293,13 @@ void SpeechRecognizer::HandleOnData(string* data) {
// Calculate the input volume to display in the UI, smoothing towards the
// new level.
- float level = (rms - kAudioMeterMinDb) / kAudioMeterDbRange;
- level = std::min(std::max(0.0f, level), 1.0f);
- if (level > audio_level_) {
- audio_level_ += (level - audio_level_) * kUpSmoothingFactor;
- } else {
- audio_level_ += (level - audio_level_) * kDownSmoothingFactor;
- }
+ float level = (rms - kAudioMeterMinDb) / kAudioMeterDbRange;
+ level = std::min(std::max(0.0f, level), 1.0f);
+ if (level > audio_level_) {
+ audio_level_ += (level - audio_level_) * kUpSmoothingFactor;
+ } else {
+ audio_level_ += (level - audio_level_) * kDownSmoothingFactor;
+ }
delegate_->SetInputVolume(caller_id_, audio_level_);
if (endpointer_.speech_input_complete()) {
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index acdbca3..9bbe65a 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1785,6 +1785,7 @@
'browser/sessions/tab_restore_service_browsertest.cc',
'browser/speech/enable_speech_input_switch_browsertest.cc',
'browser/speech/speech_input_browsertest.cc',
+ 'browser/speech/speech_input_bubble_browsertest.cc',
'browser/ssl/ssl_browser_tests.cc',
'browser/task_manager_browsertest.cc',
'browser/views/browser_actions_container_browsertest.cc',