Commit a215ef7a authored by dcaiafa@chromium.org's avatar dcaiafa@chromium.org

Implement Desktop Media Picker (Mac version) for the Desktop Capture API

This CL implements DesktopMediaPicker for the Mac used by the Desktop Capture API to present the user with a list of sources (including live thumbnails) to use.

BUG=237907

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=221874

Review URL: https://chromiumcodereview.appspot.com/23944003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@222156 0039d316-1c4b-4281-b951-d872f2087c98
parent e0c6a8d0
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h" #include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
#include "base/compiler_specific.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media/desktop_streams_registry.h" #include "chrome/browser/media/desktop_streams_registry.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h" #include "chrome/browser/media/media_capture_devices_dispatcher.h"
...@@ -87,9 +88,8 @@ bool DesktopCaptureChooseDesktopMediaFunction::RunImpl() { ...@@ -87,9 +88,8 @@ bool DesktopCaptureChooseDesktopMediaFunction::RunImpl() {
screen_capturer.Pass(), window_capturer.Pass()); screen_capturer.Pass(), window_capturer.Pass());
picker_ = g_picker_factory->CreatePicker(); picker_ = g_picker_factory->CreatePicker();
} else { } else {
// Currently DesktopMediaPicker is implemented only for platforms that // DesktopMediaPicker is not implented for all platforms yet.
// use Views. #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
model.reset(new DesktopMediaPickerModelImpl( model.reset(new DesktopMediaPickerModelImpl(
screen_capturer.Pass(), window_capturer.Pass())); screen_capturer.Pass(), window_capturer.Pass()));
picker_ = DesktopMediaPicker::Create(); picker_ = DesktopMediaPicker::Create();
......
// Copyright 2013 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.
#ifndef CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_BRIDGE_H_
#define CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_BRIDGE_H_
#include "base/basictypes.h"
#include "chrome/browser/media/desktop_media_picker_model.h"
// Protocol corresponding to |DesktopMediaPickerModel::Observer|.
@protocol DesktopMediaPickerObserver
- (void)sourceAddedAtIndex:(int)index;
- (void)sourceRemovedAtIndex:(int)index;
- (void)sourceNameChangedAtIndex:(int)index;
- (void)sourceThumbnailChangedAtIndex:(int)index;
@end
// Provides a |DesktopMediaPickerModel::Observer| implementation that forwards
// notifications to a objective-c object implementing the
// |DesktopMediaPickerObserver| protocol.
class DesktopMediaPickerBridge : public DesktopMediaPickerModel::Observer {
public:
DesktopMediaPickerBridge(id<DesktopMediaPickerObserver> observer);
virtual ~DesktopMediaPickerBridge();
// DesktopMediaPickerModel::Observer overrides
virtual void OnSourceAdded(int index) OVERRIDE;
virtual void OnSourceRemoved(int index) OVERRIDE;
virtual void OnSourceNameChanged(int index) OVERRIDE;
virtual void OnSourceThumbnailChanged(int index) OVERRIDE;
private:
id<DesktopMediaPickerObserver> observer_; // weak; owns this
DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerBridge);
};
#endif // CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_BRIDGE_H_
// Copyright 2013 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.
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_bridge.h"
DesktopMediaPickerBridge::DesktopMediaPickerBridge(
id<DesktopMediaPickerObserver> observer)
: observer_(observer) {
}
DesktopMediaPickerBridge::~DesktopMediaPickerBridge() {
}
void DesktopMediaPickerBridge::OnSourceAdded(int index) {
[observer_ sourceAddedAtIndex:index];
}
void DesktopMediaPickerBridge::OnSourceRemoved(int index) {
[observer_ sourceRemovedAtIndex:index];
}
void DesktopMediaPickerBridge::OnSourceNameChanged(int index) {
[observer_ sourceNameChangedAtIndex:index];
}
void DesktopMediaPickerBridge::OnSourceThumbnailChanged(int index) {
[observer_ sourceThumbnailChangedAtIndex:index];
}
// Copyright 2013 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.
#ifndef CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_COCOA_H_
#define CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_COCOA_H_
#import "base/mac/scoped_nsobject.h"
#include "chrome/browser/media/desktop_media_picker.h"
@class DesktopMediaPickerController;
// Cocoa's DesktopMediaPicker implementation.
class DesktopMediaPickerCocoa : public DesktopMediaPicker {
public:
DesktopMediaPickerCocoa();
virtual ~DesktopMediaPickerCocoa();
// Overridden from DesktopMediaPicker:
virtual void Show(gfx::NativeWindow context,
gfx::NativeWindow parent,
const string16& app_name,
scoped_ptr<DesktopMediaPickerModel> model,
const DoneCallback& done_callback) OVERRIDE;
private:
base::scoped_nsobject<DesktopMediaPickerController> controller_;
};
#endif // CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_COCOA_H_
// Copyright 2013 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 "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h"
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
DesktopMediaPickerCocoa::DesktopMediaPickerCocoa() {
}
DesktopMediaPickerCocoa::~DesktopMediaPickerCocoa() {
}
void DesktopMediaPickerCocoa::Show(gfx::NativeWindow context,
gfx::NativeWindow parent,
const string16& app_name,
scoped_ptr<DesktopMediaPickerModel> model,
const DoneCallback& done_callback) {
controller_.reset(
[[DesktopMediaPickerController alloc] initWithModel:model.Pass()
callback:done_callback
appName:app_name]);
[controller_ showWindow:nil];
}
// static
scoped_ptr<DesktopMediaPicker> DesktopMediaPicker::Create() {
return scoped_ptr<DesktopMediaPicker>(new DesktopMediaPickerCocoa());
}
// Copyright 2013 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.
#ifndef CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_H_
#define CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_H_
#import <Cocoa/Cocoa.h>
#import <Quartz/Quartz.h>
#include "base/callback.h"
#import "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "chrome/browser/media/desktop_media_picker.h"
#include "chrome/browser/media/desktop_media_picker_model.h"
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_bridge.h"
// A controller for the Desktop Media Picker. Presents the user with a list of
// media sources for screen-capturing, and reports the result.
@interface DesktopMediaPickerController
: NSWindowController<NSWindowDelegate, DesktopMediaPickerObserver> {
@private
// The image browser view to present sources to the user (thumbnails and
// names).
base::scoped_nsobject<IKImageBrowserView> sourceBrowser_;
// The button used to confirm the selection.
NSButton* okButton_; // weak; owned by contentView
// The button used to cancel and close the dialog.
NSButton* cancelButton_; // weak; owned by contentView
// Provides source information (including thumbnails) to fill up |items_| and
// to render in |sourceBrowser_|.
scoped_ptr<DesktopMediaPickerModel> model_;
// To be called with the user selection.
DesktopMediaPicker::DoneCallback doneCallback_;
// Array of |DesktopMediaPickerItem| used as data for |sourceBrowser_|.
base::scoped_nsobject<NSMutableArray> items_;
// C++ bridge to use as an observer to |model_|, that forwards obj-c
// notifications to this object.
scoped_ptr<DesktopMediaPickerBridge> bridge_;
// Used to create |DesktopMediaPickerItem|s with unique IDs.
int lastImageUID_;
}
// Designated initializer.
// To show the dialog, use |NSWindowController|'s |showWindow:|.
// |callback| will be called to report the user's selection.
// |appName| will be used to format the dialog's title and the label.
- (id)initWithModel:(scoped_ptr<DesktopMediaPickerModel>)model
callback:(const DesktopMediaPicker::DoneCallback&)callback
appName:(const string16&)appName;
@end
#endif // CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_H_
// Copyright 2013 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.
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
#include "base/bind.h"
#import "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
#include "content/public/browser/browser_thread.h"
#include "grit/generated_resources.h"
#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
#import "ui/base/cocoa/flipped_view.h"
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image_skia_util_mac.h"
namespace {
const int kInitialContentWidth = 620;
const int kMinimumContentWidth = 500;
const int kMinimumContentHeight = 390;
const int kThumbnailWidth = 150;
const int kThumbnailHeight = 150;
const int kFramePadding = 20;
const int kControlSpacing = 10;
const int kExcessButtonPadding = 6;
} // namespace
@interface DesktopMediaPickerController (Private)
// Populate the window with controls and views.
- (void)initializeContentsWithAppName:(const string16&)appName;
// Create a |NSTextField| with label traits given |width|. Frame height is
// automatically adjusted to fit.
- (NSTextField*)createTextFieldWithText:(NSString*)text
frameWidth:(CGFloat)width;
// Create a button with |title|, with size adjusted to fit.
- (NSButton*)createButtonWithTitle:(NSString*)title;
// Report result by invoking |doneCallback_|. The callback is invoked only on
// the first call to |reportResult:|. Subsequent calls will be no-ops.
- (void)reportResult:(content::DesktopMediaID)sourceID;
// Action handlers.
- (void)okPressed:(id)sender;
- (void)cancelPressed:(id)sender;
@end
@implementation DesktopMediaPickerController
- (id)initWithModel:(scoped_ptr<DesktopMediaPickerModel>)model
callback:(const DesktopMediaPicker::DoneCallback&)callback
appName:(const string16&)appName {
const NSUInteger kStyleMask =
NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
base::scoped_nsobject<NSWindow> window(
[[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:kStyleMask
backing:NSBackingStoreBuffered
defer:NO]);
if ((self = [super initWithWindow:window])) {
[window setDelegate:self];
[self initializeContentsWithAppName:appName];
model_ = model.Pass();
doneCallback_ = callback;
items_.reset([[NSMutableArray alloc] init]);
bridge_.reset(new DesktopMediaPickerBridge(self));
}
return self;
}
- (void)dealloc {
[sourceBrowser_ setDelegate:nil];
[sourceBrowser_ setDataSource:nil];
[super dealloc];
}
- (void)initializeContentsWithAppName:(const string16&)appName {
// Use flipped coordinates to facilitate manual layout.
const CGFloat kPaddedWidth = kInitialContentWidth - (kFramePadding * 2);
base::scoped_nsobject<FlippedView> content(
[[FlippedView alloc] initWithFrame:NSZeroRect]);
[[self window] setContentView:content];
NSPoint origin = NSMakePoint(kFramePadding, kFramePadding);
// Set the dialog's title.
NSString* titleText = l10n_util::GetNSStringF(
IDS_DESKTOP_MEDIA_PICKER_TITLE, appName);
[[self window] setTitle:titleText];
// Set the dialog's description.
NSString* descriptionText = l10n_util::GetNSStringF(
IDS_DESKTOP_MEDIA_PICKER_TEXT, appName);
NSTextField* description = [self createTextFieldWithText:descriptionText
frameWidth:kPaddedWidth];
[description setFrameOrigin:origin];
[content addSubview:description];
origin.y += NSHeight([description frame]) + kControlSpacing;
// Create the image browser.
sourceBrowser_.reset([[IKImageBrowserView alloc] initWithFrame:NSZeroRect]);
NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled;
[sourceBrowser_ setDelegate:self];
[sourceBrowser_ setDataSource:self];
[sourceBrowser_ setCellsStyleMask:cellStyle];
[sourceBrowser_ setCellSize:NSMakeSize(kThumbnailWidth, kThumbnailHeight)];
// Create a scroll view to host the image browser.
NSRect imageBrowserScrollFrame = NSMakeRect(
origin.x, origin.y, kPaddedWidth, 350);
base::scoped_nsobject<NSScrollView> imageBrowserScroll(
[[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]);
[imageBrowserScroll setHasVerticalScroller:YES];
[imageBrowserScroll setDocumentView:sourceBrowser_];
[imageBrowserScroll setBorderType:NSBezelBorder];
[imageBrowserScroll setAutoresizingMask:
NSViewWidthSizable | NSViewHeightSizable];
[content addSubview:imageBrowserScroll];
origin.y += NSHeight(imageBrowserScrollFrame) + kControlSpacing;
// Create the cancel button.
cancelButton_ =
[self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
origin.x = kInitialContentWidth - kFramePadding -
(NSWidth([cancelButton_ frame]) - kExcessButtonPadding);
[cancelButton_ setFrameOrigin:origin];
[cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[cancelButton_ setTarget:self];
[cancelButton_ setAction:@selector(cancelPressed:)];
[content addSubview:cancelButton_];
// Create the OK button.
okButton_ = [self createButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
origin.x -= kControlSpacing +
(NSWidth([okButton_ frame]) - (kExcessButtonPadding * 2));
[okButton_ setEnabled:NO];
[okButton_ setFrameOrigin:origin];
[okButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[okButton_ setTarget:self];
[okButton_ setAction:@selector(okPressed:)];
[content addSubview:okButton_];
origin.y += kFramePadding +
(NSHeight([okButton_ frame]) - kExcessButtonPadding);
// Resize window to fit.
[[[self window] contentView] setAutoresizesSubviews:NO];
[[self window] setContentSize:NSMakeSize(kInitialContentWidth, origin.y)];
[[self window] setContentMinSize:
NSMakeSize(kMinimumContentWidth, kMinimumContentHeight)];
[[[self window] contentView] setAutoresizesSubviews:YES];
}
- (void)showWindow:(id)sender {
// Signal the model to start sending thumbnails. |bridge_| is used as the
// observer, and will forward notifications to this object.
model_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
model_->StartUpdating(bridge_.get());
[self.window center];
[super showWindow:sender];
}
- (void)reportResult:(content::DesktopMediaID)sourceID {
if (doneCallback_.is_null()) {
return;
}
// Notify the |callback_| asynchronously because it may release the
// controller.
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(doneCallback_, sourceID));
doneCallback_.Reset();
}
- (void)okPressed:(id)sender {
NSIndexSet* indexes = [sourceBrowser_ selectionIndexes];
NSUInteger selectedIndex = [indexes firstIndex];
DesktopMediaPickerItem* item =
[items_ objectAtIndex:selectedIndex];
[self reportResult:[item sourceID]];
[self close];
}
- (void)cancelPressed:(id)sender {
[self reportResult:content::DesktopMediaID()];
[self close];
}
- (NSTextField*)createTextFieldWithText:(NSString*)text
frameWidth:(CGFloat)width {
NSRect frame = NSMakeRect(0, 0, width, 1);
base::scoped_nsobject<NSTextField> textField(
[[NSTextField alloc] initWithFrame:frame]);
[textField setEditable:NO];
[textField setSelectable:YES];
[textField setDrawsBackground:NO];
[textField setBezeled:NO];
[textField setStringValue:text];
[textField setFont:[NSFont systemFontOfSize:13]];
[textField setAutoresizingMask:NSViewWidthSizable];
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
return textField.autorelease();
}
- (NSButton*)createButtonWithTitle:(NSString*)title {
base::scoped_nsobject<NSButton> button(
[[NSButton alloc] initWithFrame:NSZeroRect]);
[button setButtonType:NSMomentaryPushInButton];
[button setBezelStyle:NSRoundedBezelStyle];
[button setTitle:title];
[GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
return button.autorelease();
}
#pragma mark NSWindowDelegate
- (void)windowWillClose:(NSNotification*)notification {
// Report the result if it hasn't been reported yet. |reportResult:| ensures
// that the result is only reported once.
[self reportResult:content::DesktopMediaID()];
}
#pragma mark IKImageBrowserDataSource
- (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser {
return [items_ count];
}
- (id)imageBrowser:(IKImageBrowserView *)browser
itemAtIndex:(NSUInteger)index {
return [items_ objectAtIndex:index];
}
#pragma mark IKImageBrowserDelegate
- (void)imageBrowser:(IKImageBrowserView *)browser
cellWasDoubleClickedAtIndex:(NSUInteger)index {
DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
[self reportResult:[item sourceID]];
[self close];
}
- (void)imageBrowserSelectionDidChange:(IKImageBrowserView*) aBrowser {
// Enable or disable the OK button based on whether we have a selection.
[okButton_ setEnabled:([[sourceBrowser_ selectionIndexes] count] > 0)];
}
#pragma mark DesktopMediaPickerObserver
- (void)sourceAddedAtIndex:(int)index {
const DesktopMediaPickerModel::Source& source = model_->source(index);
NSString* imageTitle = base::SysUTF16ToNSString(source.name);
base::scoped_nsobject<DesktopMediaPickerItem> item(
[[DesktopMediaPickerItem alloc] initWithSourceId:source.id
imageUID:++lastImageUID_
imageTitle:imageTitle]);
[items_ insertObject:item atIndex:index];
[sourceBrowser_ reloadData];
}
- (void)sourceRemovedAtIndex:(int)index {
if ([[sourceBrowser_ selectionIndexes] containsIndex:index]) {
// Selected item was removed. Clear selection.
[sourceBrowser_ setSelectionIndexes:[NSIndexSet indexSet]
byExtendingSelection:FALSE];
}
[items_ removeObjectAtIndex:index];
[sourceBrowser_ reloadData];
}
- (void)sourceNameChangedAtIndex:(int)index {
DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
const DesktopMediaPickerModel::Source& source = model_->source(index);
[item setImageTitle:base::SysUTF16ToNSString(source.name)];
[sourceBrowser_ reloadData];
}
- (void)sourceThumbnailChangedAtIndex:(int)index {
const DesktopMediaPickerModel::Source& source = model_->source(index);
NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail);
DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
[item setImageRepresentation:image];
[sourceBrowser_ reloadData];
}
@end // @interface DesktopMediaPickerController
// Copyright 2013 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.
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/run_loop.h"
#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest_mac.h"
@interface DesktopMediaPickerController (ExposedForTesting)
- (IKImageBrowserView*)sourceBrowser;
- (NSButton*)okButton;
- (NSArray*)items;
@end
@implementation DesktopMediaPickerController (ExposedForTesting)
- (IKImageBrowserView*)sourceBrowser {
return sourceBrowser_;
}
- (NSButton*)okButton {
return okButton_;
}
- (NSButton*)cancelButton {
return cancelButton_;
}
- (NSArray*)items {
return items_;
}
@end
class FakeDesktopMediaPickerModel : public DesktopMediaPickerModel {
public:
FakeDesktopMediaPickerModel() : observer_(NULL) {
}
void AddSource(int id) {
Source source(
content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, id),
base::Int64ToString16(id));
sources_.push_back(source);
observer_->OnSourceAdded(sources_.size() - 1);
}
void RemoveSource(int index) {
sources_.erase(sources_.begin() + index);
observer_->OnSourceRemoved(sources_.size() - 1);
}
void SetSourceThumbnail(int index) {
sources_[index].thumbnail = thumbnail_;
observer_->OnSourceThumbnailChanged(index);
}
void SetSourceName(int index, string16 name) {
sources_[index].name = name;
observer_->OnSourceNameChanged(index);
}
// DesktopMediaPickerModel implementation:
virtual void SetUpdatePeriod(base::TimeDelta period) OVERRIDE {
}
virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) OVERRIDE {
}
virtual void StartUpdating(Observer* observer) OVERRIDE {
observer_ = observer;
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150, 150);
bitmap.allocPixels();
bitmap.eraseRGB(0, 255, 0);
thumbnail_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
}
virtual int source_count() const OVERRIDE {
return sources_.size();
}
virtual const Source& source(int index) const OVERRIDE {
return sources_[index];
}
private:
std::vector<Source> sources_;
Observer* observer_;
gfx::ImageSkia thumbnail_;
};
class DesktopMediaPickerControllerTest : public CocoaTest {
public:
DesktopMediaPickerControllerTest() : callback_called_(false), model_(NULL) {
}
virtual void SetUp() OVERRIDE {
CocoaTest::SetUp();
model_ = new FakeDesktopMediaPickerModel();
DesktopMediaPicker::DoneCallback callback =
base::Bind(&DesktopMediaPickerControllerTest::OnResult,
base::Unretained(this));
controller_.reset(
[[DesktopMediaPickerController alloc]
initWithModel:scoped_ptr<DesktopMediaPickerModel>(model_)
callback:callback
appName:ASCIIToUTF16("Screenshare Test")]);
}
virtual void TearDown() OVERRIDE {
controller_.reset();
CocoaTest::TearDown();
}
bool WaitForCallback() {
if (!callback_called_) {
base::RunLoop().RunUntilIdle();
}
return callback_called_;
}
protected:
void OnResult(content::DesktopMediaID source) {
EXPECT_FALSE(callback_called_);
callback_called_ = true;
source_reported_ = source;
}
content::TestBrowserThreadBundle thread_bundle_;
bool callback_called_;
content::DesktopMediaID source_reported_;
FakeDesktopMediaPickerModel* model_;
base::scoped_nsobject<DesktopMediaPickerController> controller_;
};
TEST_F(DesktopMediaPickerControllerTest, ShowAndDismiss) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
NSArray* items = [controller_ items];
EXPECT_EQ(2U, [items count]);
EXPECT_NSEQ(@"0", [[items objectAtIndex:0] imageTitle]);
EXPECT_EQ(nil, [[items objectAtIndex:0] imageRepresentation]);
EXPECT_NSEQ(@"1", [[items objectAtIndex:1] imageTitle]);
EXPECT_TRUE([[items objectAtIndex:1] imageRepresentation] != nil);
}
TEST_F(DesktopMediaPickerControllerTest, ClickOK) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->SetSourceThumbnail(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
EXPECT_EQ(2U, [[controller_ items] count]);
EXPECT_FALSE([[controller_ okButton] isEnabled]);
NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:1];
[[controller_ sourceBrowser] setSelectionIndexes:indexSet
byExtendingSelection:NO];
EXPECT_TRUE([[controller_ okButton] isEnabled]);
[[controller_ okButton] performClick:nil];
EXPECT_TRUE(WaitForCallback());
EXPECT_EQ(model_->source(1).id, source_reported_);
}
TEST_F(DesktopMediaPickerControllerTest, ClickCancel) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->SetSourceThumbnail(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
[[controller_ cancelButton] performClick:nil];
EXPECT_TRUE(WaitForCallback());
EXPECT_EQ(content::DesktopMediaID(), source_reported_);
}
TEST_F(DesktopMediaPickerControllerTest, CloseWindow) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->SetSourceThumbnail(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
[controller_ close];
EXPECT_TRUE(WaitForCallback());
EXPECT_EQ(content::DesktopMediaID(), source_reported_);
}
TEST_F(DesktopMediaPickerControllerTest, UpdateThumbnail) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->SetSourceThumbnail(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
NSArray* items = [controller_ items];
EXPECT_EQ(2U, [items count]);
NSUInteger version = [[items objectAtIndex:0] imageVersion];
model_->SetSourceThumbnail(0);
EXPECT_NE(version, [[items objectAtIndex:0] imageVersion]);
}
TEST_F(DesktopMediaPickerControllerTest, UpdateName) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->SetSourceThumbnail(0);
model_->AddSource(1);
model_->SetSourceThumbnail(1);
NSArray* items = [controller_ items];
EXPECT_EQ(2U, [items count]);
NSUInteger version = [[items objectAtIndex:0] imageVersion];
model_->SetSourceThumbnail(0);
EXPECT_NE(version, [[items objectAtIndex:0] imageVersion]);
}
TEST_F(DesktopMediaPickerControllerTest, RemoveSource) {
[controller_ showWindow:nil];
model_->AddSource(0);
model_->AddSource(1);
model_->AddSource(2);
model_->SetSourceName(1, ASCIIToUTF16("foo"));
NSArray* items = [controller_ items];
EXPECT_EQ(3U, [items count]);
EXPECT_NSEQ(@"foo", [[items objectAtIndex:1] imageTitle]);
}
// Copyright 2013 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.
#ifndef CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_ITEM_H_
#define CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_ITEM_H_
#import <AppKit/AppKit.h>
#import "base/mac/scoped_nsobject.h"
#include "chrome/browser/media/desktop_media_picker_model.h"
// Stores the data representing a |DesktopMediaPicker| source for displaying in
// a |IKImageBrowserView|. Implements the |IKImageBrowserItem| informal
// protocol.
@interface DesktopMediaPickerItem : NSObject {
@private
content::DesktopMediaID sourceID_;
base::scoped_nsobject<NSString> imageUID_;
base::scoped_nsobject<NSString> imageTitle_;
base::scoped_nsobject<NSImage> image_;
NSUInteger imageVersion_;
}
// Designated initializer.
// |sourceID| is the corresponding source's ID as provided by the model.
// |imageUID| is a unique number in the context of the |IKImageBrowserView|
// instance.
// |imageTitle| is the source's name to be used as the label in
// |IKImageBrowserView|.
- (id)initWithSourceId:(content::DesktopMediaID)sourceID
imageUID:(int)imageUID
imageTitle:(NSString*)imageTitle;
// Returns the source's ID.
- (content::DesktopMediaID)sourceID;
// Sets the image of the item to be displayed in |IKImageBrowserView|.
- (void)setImageRepresentation:(NSImage*)image;
// Sets the label of the item to be displayed in |IKImageBrowserView|.
- (void)setImageTitle:(NSString*)imageTitle;
@end
#endif // CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_ITEM_H_
// Copyright 2013 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.
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
#import <Quartz/Quartz.h>
#include "chrome/browser/media/desktop_media_picker_model.h"
@implementation DesktopMediaPickerItem
- (id)initWithSourceId:(content::DesktopMediaID)sourceID
imageUID:(int)imageUID
imageTitle:(NSString*)imageTitle {
if ((self = [super init])) {
sourceID_ = sourceID;
imageUID_.reset([[NSString stringWithFormat:@"%d", imageUID] retain]);
imageTitle_.reset([imageTitle retain]);
}
return self;
}
- (content::DesktopMediaID)sourceID {
return sourceID_;
}
- (void)setImageRepresentation:(NSImage*)image {
image_.reset([image retain]);
++imageVersion_;
}
- (void)setImageTitle:(NSString*)imageTitle {
imageTitle_.reset([imageTitle copy]);
}
#pragma mark IKImageBrowserItem
- (NSString*)imageUID {
return imageUID_;
}
- (NSString*)imageRepresentationType {
return IKImageBrowserNSImageRepresentationType;
}
- (NSString*)imageTitle {
return imageTitle_.get();
}
- (NSUInteger)imageVersion {
return imageVersion_;
}
- (id)imageRepresentation {
return image_.get();
}
@end // @interface DesktopMediaPickerItem
...@@ -804,6 +804,14 @@ ...@@ -804,6 +804,14 @@
'browser/ui/cocoa/login_prompt_cocoa.h', 'browser/ui/cocoa/login_prompt_cocoa.h',
'browser/ui/cocoa/login_prompt_cocoa.mm', 'browser/ui/cocoa/login_prompt_cocoa.mm',
'browser/ui/cocoa/main_menu_item.h', 'browser/ui/cocoa/main_menu_item.h',
'browser/ui/cocoa/media_picker/desktop_media_picker_bridge.h',
'browser/ui/cocoa/media_picker/desktop_media_picker_bridge.mm',
'browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h',
'browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm',
'browser/ui/cocoa/media_picker/desktop_media_picker_controller.h',
'browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm',
'browser/ui/cocoa/media_picker/desktop_media_picker_item.h',
'browser/ui/cocoa/media_picker/desktop_media_picker_item.mm',
'browser/ui/cocoa/menu_button.h', 'browser/ui/cocoa/menu_button.h',
'browser/ui/cocoa/menu_button.mm', 'browser/ui/cocoa/menu_button.mm',
'browser/ui/cocoa/multi_key_equivalent_button.h', 'browser/ui/cocoa/multi_key_equivalent_button.h',
...@@ -2994,6 +3002,11 @@ ...@@ -2994,6 +3002,11 @@
'include_dirs': [ 'include_dirs': [
'../third_party/GTM', '../third_party/GTM',
], ],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Quartz.framework',
],
},
'actions': [ 'actions': [
{ {
# This action is used to extract the localization data from xib # This action is used to extract the localization data from xib
......
...@@ -1521,6 +1521,7 @@ ...@@ -1521,6 +1521,7 @@
'browser/ui/cocoa/location_bar/image_decoration_unittest.mm', 'browser/ui/cocoa/location_bar/image_decoration_unittest.mm',
'browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm', 'browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm',
'browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm', 'browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm',
'browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm',
'browser/ui/cocoa/menu_button_unittest.mm', 'browser/ui/cocoa/menu_button_unittest.mm',
'browser/ui/cocoa/nine_part_button_cell_unittest.mm', 'browser/ui/cocoa/nine_part_button_cell_unittest.mm',
'browser/ui/cocoa/notifications/balloon_controller_unittest.mm', 'browser/ui/cocoa/notifications/balloon_controller_unittest.mm',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment