| // 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<HomeCard::State>(final_state + 1)); |
| } else { |
| final_state = std::max(HomeCard::VISIBLE_CENTERED, |
| static_cast<HomeCard::State>(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<HomeCard::State>(bigger_state + 1), |
| bigger_state, |
| progress); |
| } |
| |
| } // namespace athena |