// Copyright 2014 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 "athena/home/home_card_gesture_manager.h" #include "athena/home/home_card_constants.h" #include "ui/events/event.h" namespace athena { namespace { // The maximum height, in pixels, of a home card with final state // VISIBLE_MINIMIZED. const int kMinimizedFinalStateMaxHeight = 50 + kHomeCardMinimizedHeight; // The maximum height, in pixels, of an initially centered home card with final // state VISIBLE_MINIMIZED. const int kMinimizedFinalStateMaxHeightInitiallyCentered = 90 + kHomeCardMinimizedHeight; // The minimum height, as a percentage of the screen height, of a home card with // final state VISIBLE_CENTERED. const float kCenteredFinalStateMinScreenRatio = 0.5f; // The minimum height, as a percentage of the screen height, of an initially // minimized home card with final state VISIBLE_CENTERED. const float kCenteredFinalStateMinScreenRatioInitiallyMinimized = 0.3f; } HomeCardGestureManager::HomeCardGestureManager(Delegate* delegate, const gfx::Rect& screen_bounds) : delegate_(delegate), original_state_(HomeCard::HIDDEN), y_offset_(0), last_estimated_height_(0), screen_bounds_(screen_bounds) {} HomeCardGestureManager::~HomeCardGestureManager() {} void HomeCardGestureManager::ProcessGestureEvent(ui::GestureEvent* event) { switch (event->type()) { case ui::ET_GESTURE_SCROLL_BEGIN: y_offset_ = event->location().y(); original_state_ = HomeCard::Get()->GetState(); DCHECK_NE(HomeCard::HIDDEN, original_state_); event->SetHandled(); break; case ui::ET_GESTURE_SCROLL_END: event->SetHandled(); delegate_->OnGestureEnded(GetFinalState(), false); break; case ui::ET_GESTURE_SCROLL_UPDATE: UpdateScrollState(*event); break; case ui::ET_SCROLL_FLING_START: { const ui::GestureEventDetails& details = event->details(); const float kFlingCompletionVelocity = 100.0f; HomeCard::State final_state = GetFinalState(); // When the user does not drag far enough to switch the final state, but // a fling happens at the end of the gesture, the state should change // based on the direction of the fling. // Checking |final_state| == |original_state| may cause unexpected results // for gestures where the user flings in the opposite direction that they // moved the home card (e.g. drag home card up from minimized state and // then fling down) // TODO(mukai): Consider this case once reported. bool is_fling = ::fabs(details.velocity_y()) > kFlingCompletionVelocity; if (final_state == original_state_ && is_fling) { if (details.velocity_y() > 0) { final_state = std::min(HomeCard::VISIBLE_MINIMIZED, static_cast(final_state + 1)); } else { final_state = std::max(HomeCard::VISIBLE_CENTERED, static_cast(final_state - 1)); } } delegate_->OnGestureEnded(final_state, is_fling); break; } default: // do nothing. break; } } HomeCard::State HomeCardGestureManager::GetFinalState() const { int max_height = (original_state_ == HomeCard::VISIBLE_CENTERED) ? kMinimizedFinalStateMaxHeightInitiallyCentered : kMinimizedFinalStateMaxHeight; if (last_estimated_height_ < max_height) return HomeCard::VISIBLE_MINIMIZED; float ratio = (original_state_ == HomeCard::VISIBLE_MINIMIZED) ? kCenteredFinalStateMinScreenRatioInitiallyMinimized : kCenteredFinalStateMinScreenRatio; if (last_estimated_height_ < screen_bounds_.height() * ratio) return HomeCard::VISIBLE_BOTTOM; return HomeCard::VISIBLE_CENTERED; } void HomeCardGestureManager::UpdateScrollState(const ui::GestureEvent& event) { last_estimated_height_ = screen_bounds_.height() - event.root_location().y() + y_offset_; if (last_estimated_height_ <= kHomeCardMinimizedHeight) { delegate_->OnGestureProgressed( HomeCard::VISIBLE_BOTTOM, HomeCard::VISIBLE_MINIMIZED, 1.0f); return; } HomeCard::State bigger_state = HomeCard::VISIBLE_BOTTOM; float smaller_height = kHomeCardMinimizedHeight; float bigger_height = kHomeCardHeight; if (last_estimated_height_ > kHomeCardHeight) { bigger_state = HomeCard::VISIBLE_CENTERED; smaller_height = kHomeCardHeight; bigger_height = screen_bounds_.height(); } // The finger is between two states. float progress = (last_estimated_height_ - smaller_height) / (bigger_height - smaller_height); progress = std::min(1.0f, std::max(0.0f, progress)); delegate_->OnGestureProgressed( static_cast(bigger_state + 1), bigger_state, progress); } } // namespace athena