diff options
author | bruthig <bruthig@chromium.org> | 2015-05-07 15:08:37 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-07 22:09:14 +0000 |
commit | 1a43e72e774c030d2916219e109cb18e8b906421 (patch) | |
tree | 9c6558f0761af3b8760ba6c1299769e4f884d743 /ash | |
parent | 5595f3bb78465d791781b8c6739d054fd31b20d3 (diff) | |
download | chromium_src-1a43e72e774c030d2916219e109cb18e8b906421.zip chromium_src-1a43e72e774c030d2916219e109cb18e8b906421.tar.gz chromium_src-1a43e72e774c030d2916219e109cb18e8b906421.tar.bz2 |
Added UMA metrics to record the number of items in the shelf.
Added Ash.Shelf.NumberOfItems, Ash.Shelf.NumberOfPinnedItems,
Ash.Shelf.NumberOfUnpinnedItems histograms to track the number of items in
the shelf.
Note: This is a re-landing of https://codereview.chromium.org/1055963002/
with necessary fixes to prevent crashes.
TEST=UserMetricsRecorderTest.VerifyStatsRecordedWhenUserNotInActiveDesktopEnvironment
TEST=UserMetricsRecorderTest.VerifyStatsRecordedWhenUserInActiveDesktopEnvironment
TEST=UserMetricsRecorderTest.ValuesRecordedByRecordShelfItemCounts
TEST=Verified internal apps (ie. Settings and Task Manager) don't cause a
crash. (See www.crbug.com/474702)
BUG=471369
Review URL: https://codereview.chromium.org/1088243002
Cr-Commit-Position: refs/heads/master@{#328851}
Diffstat (limited to 'ash')
-rw-r--r-- | ash/metrics/user_metrics_recorder.cc | 32 | ||||
-rw-r--r-- | ash/metrics/user_metrics_recorder_unittest.cc | 60 | ||||
-rw-r--r-- | ash/shelf/shelf_delegate.h | 5 | ||||
-rw-r--r-- | ash/shelf/shelf_view_unittest.cc | 56 | ||||
-rw-r--r-- | ash/shell/shelf_delegate_impl.cc | 4 | ||||
-rw-r--r-- | ash/shell/shelf_delegate_impl.h | 1 | ||||
-rw-r--r-- | ash/test/test_shelf_delegate.cc | 39 | ||||
-rw-r--r-- | ash/test/test_shelf_delegate.h | 24 |
8 files changed, 189 insertions, 32 deletions
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc index dee488b..328333e 100644 --- a/ash/metrics/user_metrics_recorder.cc +++ b/ash/metrics/user_metrics_recorder.cc @@ -5,7 +5,10 @@ #include "ash/metrics/user_metrics_recorder.h" #include "ash/session/session_state_delegate.h" +#include "ash/shelf/shelf_delegate.h" +#include "ash/shelf/shelf_item_types.h" #include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" @@ -148,6 +151,34 @@ int GetNumVisibleWindowsInPrimaryDisplay() { return visible_window_count; } +// Records the number of items in the shelf as an UMA statistic. +void RecordShelfItemCounts() { + ShelfDelegate* shelf_delegate = Shell::GetInstance()->GetShelfDelegate(); + int pinned_item_count = 0; + int unpinned_item_count = 0; + + for (const ShelfItem& shelf_item : + Shell::GetInstance()->shelf_model()->items()) { + if (shelf_item.type != TYPE_APP_LIST) { + // Internal ash apps do not have an app id and thus will always be counted + // as unpinned. + if (shelf_delegate->HasShelfIDToAppIDMapping(shelf_item.id) && + shelf_delegate->IsAppPinned( + shelf_delegate->GetAppIDForShelfID(shelf_item.id))) { + ++pinned_item_count; + } else { + ++unpinned_item_count; + } + } + } + + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfItems", + pinned_item_count + unpinned_item_count); + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfPinnedItems", pinned_item_count); + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfUnpinnedItems", + unpinned_item_count); +} + } // namespace UserMetricsRecorder::UserMetricsRecorder() { @@ -574,6 +605,7 @@ void UserMetricsRecorder::RecordPeriodicMetrics() { } if (IsUserInActiveDesktopEnvironment()) { + RecordShelfItemCounts(); UMA_HISTOGRAM_COUNTS_100("Ash.NumberOfVisibleWindowsInPrimaryDisplay", GetNumVisibleWindowsInPrimaryDisplay()); } diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc index 04cbd1c..f2ffd32 100644 --- a/ash/metrics/user_metrics_recorder_unittest.cc +++ b/ash/metrics/user_metrics_recorder_unittest.cc @@ -4,9 +4,12 @@ #include "ash/metrics/user_metrics_recorder.h" +#include "ash/shelf/shelf_model.h" +#include "ash/shelf/shelf_util.h" #include "ash/shell.h" #include "ash/system/user/login_status.h" #include "ash/test/ash_test_base.h" +#include "ash/test/test_shelf_delegate.h" #include "ash/test/test_system_tray_delegate.h" #include "ash/test/user_metrics_recorder_test_api.h" #include "base/memory/scoped_ptr.h" @@ -22,6 +25,13 @@ const char kAsh_NumberOfVisibleWindowsInPrimaryDisplay[] = const char kAsh_ActiveWindowShowTypeOverTime[] = "Ash.ActiveWindowShowTypeOverTime"; +const char kAsh_Shelf_NumberOfItems[] = "Ash.Shelf.NumberOfItems"; + +const char kAsh_Shelf_NumberOfPinnedItems[] = "Ash.Shelf.NumberOfPinnedItems"; + +const char kAsh_Shelf_NumberOfUnpinnedItems[] = + "Ash.Shelf.NumberOfUnpinnedItems"; + } // namespace // Test fixture for the UserMetricsRecorder class. @@ -41,6 +51,9 @@ class UserMetricsRecorderTest : public test::AshTestBase { // environment. void SetUserInActiveDesktopEnvironment(bool is_active); + // Creates an aura::Window. + aura::Window* CreateTestWindow(); + test::UserMetricsRecorderTestAPI* user_metrics_recorder_test_api() { return user_metrics_recorder_test_api_.get(); } @@ -94,6 +107,12 @@ void UserMetricsRecorderTest::SetUserInActiveDesktopEnvironment( } } +aura::Window* UserMetricsRecorderTest::CreateTestWindow() { + aura::Window* window = CreateTestWindowInShellWithDelegateAndType( + nullptr, ui::wm::WINDOW_TYPE_NORMAL, 0, gfx::Rect()); + return window; +} + // Verifies the return value of IsUserInActiveDesktopEnvironment() for the // different login status values. TEST_F(UserMetricsRecorderTest, VerifyIsUserInActiveDesktopEnvironmentValues) { @@ -138,6 +157,9 @@ TEST_F(UserMetricsRecorderTest, user_metrics_recorder_test_api()->RecordPeriodicMetrics(); histograms().ExpectTotalCount(kAsh_NumberOfVisibleWindowsInPrimaryDisplay, 0); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfItems, 0); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfPinnedItems, 0); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfUnpinnedItems, 0); } // Verifies that the IsUserInActiveDesktopEnvironment() dependent stats are @@ -148,6 +170,9 @@ TEST_F(UserMetricsRecorderTest, user_metrics_recorder_test_api()->RecordPeriodicMetrics(); histograms().ExpectTotalCount(kAsh_NumberOfVisibleWindowsInPrimaryDisplay, 1); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfItems, 1); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfPinnedItems, 1); + histograms().ExpectTotalCount(kAsh_Shelf_NumberOfUnpinnedItems, 1); } // Verifies recording of stats which are always recorded by @@ -159,4 +184,39 @@ TEST_F(UserMetricsRecorderTest, VerifyStatsRecordedByRecordPeriodicMetrics) { histograms().ExpectTotalCount(kAsh_ActiveWindowShowTypeOverTime, 1); } +// Verify the shelf item counts recorded by the +// UserMetricsRecorder::RecordPeriodicMetrics() method. +TEST_F(UserMetricsRecorderTest, ValuesRecordedByRecordShelfItemCounts) { + test::TestShelfDelegate* test_shelf_delegate = + test::TestShelfDelegate::instance(); + SetUserInActiveDesktopEnvironment(true); + + // Make sure the shelf contains the app list launcher button. + const ShelfItems& shelf_items = Shell::GetInstance()->shelf_model()->items(); + ASSERT_EQ(1u, shelf_items.size()); + ASSERT_EQ(TYPE_APP_LIST, shelf_items[0].type); + + aura::Window* pinned_window_with_app_id_1 = CreateTestWindow(); + test_shelf_delegate->AddShelfItem(pinned_window_with_app_id_1, "app_id_1"); + test_shelf_delegate->PinAppWithID("app_id_1"); + + aura::Window* pinned_window_with_app_id_2 = CreateTestWindow(); + test_shelf_delegate->AddShelfItem(pinned_window_with_app_id_2, "app_id_2"); + test_shelf_delegate->PinAppWithID("app_id_2"); + + aura::Window* unpinned_window_with_app_id_3 = CreateTestWindow(); + test_shelf_delegate->AddShelfItem(unpinned_window_with_app_id_3, "app_id_3"); + + aura::Window* unpinned_window_4 = CreateTestWindow(); + test_shelf_delegate->AddShelfItem(unpinned_window_4); + + aura::Window* unpinned_window_5 = CreateTestWindow(); + test_shelf_delegate->AddShelfItem(unpinned_window_5); + + user_metrics_recorder_test_api()->RecordPeriodicMetrics(); + histograms().ExpectBucketCount(kAsh_Shelf_NumberOfItems, 5, 1); + histograms().ExpectBucketCount(kAsh_Shelf_NumberOfPinnedItems, 2, 1); + histograms().ExpectBucketCount(kAsh_Shelf_NumberOfUnpinnedItems, 3, 1); +} + } // namespace ash diff --git a/ash/shelf/shelf_delegate.h b/ash/shelf/shelf_delegate.h index 4900bd0..a94ec11 100644 --- a/ash/shelf/shelf_delegate.h +++ b/ash/shelf/shelf_delegate.h @@ -28,7 +28,12 @@ class ASH_EXPORT ShelfDelegate { // Get the shelf ID from an application ID. virtual ShelfID GetShelfIDForAppID(const std::string& app_id) = 0; + // Checks whether a mapping exists from the ShelfID |id| to an app id. + virtual bool HasShelfIDToAppIDMapping(ShelfID id) const = 0; + // Get the application ID for a given shelf ID. + // |HasShelfIDToAppIDMapping(ShelfID)| should be called first to ensure the + // ShelfID can be successfully mapped to an app id. virtual const std::string& GetAppIDForShelfID(ShelfID id) = 0; // Pins an app with |app_id| to shelf. A running instance will get pinned. diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 640a5c5..6526fed 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc @@ -238,14 +238,17 @@ TEST_F(ShelfViewIconObserverTest, BoundsChanged) { //////////////////////////////////////////////////////////////////////////////// // ShelfView tests. -// Simple ShelfDelegate implmentation for ShelfViewTest.OverflowBubbleSize -// and CheckDragAndDropFromOverflowBubbleToShelf +// A ShelfDelegate test double that will always convert between ShelfIDs and app +// ids. This does not support pinning and unpinning operations however CanPin() +// will return true and the return value of IsAppPinned(...) is configurable. class TestShelfDelegateForShelfView : public ShelfDelegate { public: explicit TestShelfDelegateForShelfView(ShelfModel* model) : model_(model) {} ~TestShelfDelegateForShelfView() override {} + void set_is_app_pinned(bool is_pinned) { is_app_pinned_ = is_pinned; } + // ShelfDelegate overrides: void OnShelfCreated(Shelf* shelf) override {} @@ -257,6 +260,8 @@ class TestShelfDelegateForShelfView : public ShelfDelegate { return id; } + bool HasShelfIDToAppIDMapping(ShelfID id) const override { return true; } + const std::string& GetAppIDForShelfID(ShelfID id) override { // Use |app_id_| member variable because returning a reference to local // variable is not allowed. @@ -264,29 +269,22 @@ class TestShelfDelegateForShelfView : public ShelfDelegate { return app_id_; } - void PinAppWithID(const std::string& app_id) override {} + void PinAppWithID(const std::string& app_id) override { NOTREACHED(); } bool IsAppPinned(const std::string& app_id) override { - // Returns true for ShelfViewTest.OverflowBubbleSize. To test ripping off in - // that test, an item is already pinned state. - return true; + return is_app_pinned_; } bool CanPin() const override { return true; } - void UnpinAppWithID(const std::string& app_id) override { - ShelfID id = 0; - EXPECT_TRUE(base::StringToInt(app_id, &id)); - ASSERT_GT(id, 0); - int index = model_->ItemIndexByID(id); - ASSERT_GE(index, 0); - - model_->RemoveItemAt(index); - } + void UnpinAppWithID(const std::string& app_id) override { NOTREACHED(); } private: ShelfModel* model_; + // Tracks whether apps are pinned or not. + bool is_app_pinned_ = false; + // Temp member variable for returning a value. See the comment in the // GetAppIDForShelfID(). std::string app_id_; @@ -316,6 +314,8 @@ class ShelfViewTest : public AshTestBase { test_api_.reset(new ShelfViewTestAPI(shelf_view_)); test_api_->SetAnimationDuration(1); // Speeds up animation for test. + ReplaceShelfDelegate(); + item_manager_ = Shell::GetInstance()->shelf_item_delegate_manager(); DCHECK(item_manager_); @@ -324,6 +324,7 @@ class ShelfViewTest : public AshTestBase { } void TearDown() override { + shelf_delegate_ = nullptr; test_api_.reset(); AshTestBase::TearDown(); } @@ -615,14 +616,15 @@ class ShelfViewTest : public AshTestBase { return model_->items()[index].id; } - void ReplaceShelfDelegateForRipOffTest() { + void ReplaceShelfDelegate() { // Replace ShelfDelegate. - test::ShellTestApi test_api(Shell::GetInstance()); - test_api.SetShelfDelegate(NULL); - ShelfDelegate* delegate = new TestShelfDelegateForShelfView(model_); - test_api.SetShelfDelegate(delegate); - test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).SetShelfDelegate(delegate); - test_api_->SetShelfDelegate(delegate); + test::ShellTestApi shell_test_api(Shell::GetInstance()); + shell_test_api.SetShelfDelegate(NULL); + shelf_delegate_ = new TestShelfDelegateForShelfView(model_); + shell_test_api.SetShelfDelegate(shelf_delegate_); + test::ShelfTestAPI(Shelf::ForPrimaryDisplay()) + .SetShelfDelegate(shelf_delegate_); + test_api_->SetShelfDelegate(shelf_delegate_); } ShelfModel* model_; @@ -630,6 +632,9 @@ class ShelfViewTest : public AshTestBase { int browser_index_; ShelfItemDelegateManager* item_manager_; + // Owned by ash::Shell. + TestShelfDelegateForShelfView* shelf_delegate_; + scoped_ptr<ShelfViewTestAPI> test_api_; private: @@ -1501,9 +1506,7 @@ TEST_F(ShelfViewTest, ResizeDuringOverflowAddAnimation) { // Checks the overflow bubble size when an item is ripped off and re-inserted. TEST_F(ShelfViewTest, OverflowBubbleSize) { - // Replace current ShelfDelegate with TestShelfDelegateForShelfView. - ReplaceShelfDelegateForRipOffTest(); - + shelf_delegate_->set_is_app_pinned(true); AddButtonsUntilOverflow(); // Add one more button to prevent the overflow bubble to disappear upon // dragging an item out on windows (flakiness, see crbug.com/436131). @@ -1721,9 +1724,6 @@ TEST_F(ShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) { // Checks various drag and drop operations from OverflowBubble to Shelf. TEST_F(ShelfViewTest, CheckDragAndDropFromOverflowBubbleToShelf) { - // Replace current ShelfDelegate with TestShelfDelegateForShelfView. - ReplaceShelfDelegateForRipOffTest(); - AddButtonsUntilOverflow(); // Add one more button to prevent the overflow bubble to disappear upon // dragging an item out on windows (flakiness, see crbug.com/425097). diff --git a/ash/shell/shelf_delegate_impl.cc b/ash/shell/shelf_delegate_impl.cc index dfebf94..273ce2a 100644 --- a/ash/shell/shelf_delegate_impl.cc +++ b/ash/shell/shelf_delegate_impl.cc @@ -30,6 +30,10 @@ ShelfID ShelfDelegateImpl::GetShelfIDForAppID(const std::string& app_id) { return 0; } +bool ShelfDelegateImpl::HasShelfIDToAppIDMapping(ShelfID id) const { + return false; +} + const std::string& ShelfDelegateImpl::GetAppIDForShelfID(ShelfID id) { return base::EmptyString(); } diff --git a/ash/shell/shelf_delegate_impl.h b/ash/shell/shelf_delegate_impl.h index 9d7247e..32ca7ab 100644 --- a/ash/shell/shelf_delegate_impl.h +++ b/ash/shell/shelf_delegate_impl.h @@ -28,6 +28,7 @@ class ShelfDelegateImpl : public ShelfDelegate { void OnShelfCreated(Shelf* shelf) override; void OnShelfDestroyed(Shelf* shelf) override; ShelfID GetShelfIDForAppID(const std::string& app_id) override; + bool HasShelfIDToAppIDMapping(ShelfID id) const override; const std::string& GetAppIDForShelfID(ShelfID id) override; void PinAppWithID(const std::string& app_id) override; bool IsAppPinned(const std::string& app_id) override; diff --git a/ash/test/test_shelf_delegate.cc b/ash/test/test_shelf_delegate.cc index 7fced01..b3666b7 100644 --- a/ash/test/test_shelf_delegate.cc +++ b/ash/test/test_shelf_delegate.cc @@ -33,6 +33,12 @@ void TestShelfDelegate::AddShelfItem(aura::Window* window) { } void TestShelfDelegate::AddShelfItem(aura::Window* window, + const std::string& app_id) { + AddShelfItem(window, STATUS_CLOSED); + AddShelfIDToAppIDMapping(GetShelfIDForWindow(window), app_id); +} + +void TestShelfDelegate::AddShelfItem(aura::Window* window, ShelfItemStatus status) { ShelfItem item; if (window->type() == ui::wm::WINDOW_TYPE_PANEL) @@ -53,13 +59,20 @@ void TestShelfDelegate::AddShelfItem(aura::Window* window, } void TestShelfDelegate::RemoveShelfItemForWindow(aura::Window* window) { - ShelfID id = GetShelfIDForWindow(window); - if (id == 0) + ShelfID shelf_id = GetShelfIDForWindow(window); + if (shelf_id == 0) return; - int index = model_->ItemIndexByID(id); + int index = model_->ItemIndexByID(shelf_id); DCHECK_NE(-1, index); model_->RemoveItemAt(index); window->RemoveObserver(this); + if (HasShelfIDToAppIDMapping(shelf_id)) { + const std::string& app_id = GetAppIDForShelfID(shelf_id); + if (IsAppPinned(app_id)) + UnpinAppWithID(app_id); + if (HasShelfIDToAppIDMapping(shelf_id)) + RemoveShelfIDToAppIDMapping(shelf_id); + } } void TestShelfDelegate::OnWindowDestroying(aura::Window* window) { @@ -82,11 +95,20 @@ void TestShelfDelegate::OnShelfDestroyed(Shelf* shelf) { } ShelfID TestShelfDelegate::GetShelfIDForAppID(const std::string& app_id) { + for (auto const& iter : shelf_id_to_app_id_map_) { + if (iter.second == app_id) + return iter.first; + } return 0; } +bool TestShelfDelegate::HasShelfIDToAppIDMapping(ShelfID id) const { + return shelf_id_to_app_id_map_.find(id) != shelf_id_to_app_id_map_.end(); +} + const std::string& TestShelfDelegate::GetAppIDForShelfID(ShelfID id) { - return base::EmptyString(); + DCHECK_GT(shelf_id_to_app_id_map_.count(id), 0u); + return shelf_id_to_app_id_map_[id]; } void TestShelfDelegate::PinAppWithID(const std::string& app_id) { @@ -105,5 +127,14 @@ void TestShelfDelegate::UnpinAppWithID(const std::string& app_id) { pinned_apps_.erase(app_id); } +void TestShelfDelegate::AddShelfIDToAppIDMapping(ShelfID shelf_id, + const std::string& app_id) { + shelf_id_to_app_id_map_[shelf_id] = app_id; +} + +void TestShelfDelegate::RemoveShelfIDToAppIDMapping(ShelfID shelf_id) { + shelf_id_to_app_id_map_.erase(shelf_id); +} + } // namespace test } // namespace ash diff --git a/ash/test/test_shelf_delegate.h b/ash/test/test_shelf_delegate.h index 8d940f1..342d144 100644 --- a/ash/test/test_shelf_delegate.h +++ b/ash/test/test_shelf_delegate.h @@ -7,6 +7,7 @@ #include <map> #include <set> +#include <string> #include "ash/shelf/shelf_delegate.h" #include "base/compiler_specific.h" @@ -25,8 +26,21 @@ class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver { explicit TestShelfDelegate(ShelfModel* model); ~TestShelfDelegate() override; + // Adds a ShelfItem for the given |window|. The ShelfItem's status will be + // STATUS_CLOSED. void AddShelfItem(aura::Window* window); + + // Adds a ShelfItem for the given |window| and adds a mapping from the added + // ShelfItem's ShelfID to the given |app_id|. The ShelfItem's status will be + // STATUS_CLOSED. + void AddShelfItem(aura::Window* window, const std::string& app_id); + + // Adds a ShelfItem for the given |window| with the specified |status|. void AddShelfItem(aura::Window* window, ShelfItemStatus status); + + // Removes the ShelfItem for the specified |window| and unpins it if it was + // pinned. The |window|'s ShelfID to app id mapping will be removed if it + // exists. void RemoveShelfItemForWindow(aura::Window* window); static TestShelfDelegate* instance() { return instance_; } @@ -39,6 +53,7 @@ class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver { void OnShelfCreated(Shelf* shelf) override; void OnShelfDestroyed(Shelf* shelf) override; ShelfID GetShelfIDForAppID(const std::string& app_id) override; + bool HasShelfIDToAppIDMapping(ShelfID id) const override; const std::string& GetAppIDForShelfID(ShelfID id) override; void PinAppWithID(const std::string& app_id) override; bool CanPin() const override; @@ -46,12 +61,21 @@ class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver { void UnpinAppWithID(const std::string& app_id) override; private: + // Adds a mapping from a ShelfID to an app id. + void AddShelfIDToAppIDMapping(ShelfID shelf_id, const std::string& app_id); + + // Removes the mapping from a ShelfID to an app id. + void RemoveShelfIDToAppIDMapping(ShelfID shelf_id); + static TestShelfDelegate* instance_; ShelfModel* model_; std::set<std::string> pinned_apps_; + // Tracks the ShelfID to app id mappings. + std::map<ShelfID, std::string> shelf_id_to_app_id_map_; + DISALLOW_COPY_AND_ASSIGN(TestShelfDelegate); }; |