1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141

ash / wm / tablet_mode / tablet_mode_toggle_fullscreen_event_handler.cc [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.h"

#include "ash/public/cpp/shelf_config.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"

namespace ash {
namespace {

// The height of the area in which a touch operation leads to exiting the
// full screen mode.
constexpr int kLeaveFullScreenAreaHeightInPixel = 2;

}  // namespace

TabletModeToggleFullscreenEventHandler::
    TabletModeToggleFullscreenEventHandler() {
  Shell::Get()->AddPreTargetHandler(this);
}

TabletModeToggleFullscreenEventHandler::
    ~TabletModeToggleFullscreenEventHandler() {
  ResetDragData();
  Shell::Get()->RemovePreTargetHandler(this);
}

void TabletModeToggleFullscreenEventHandler::OnTouchEvent(
    ui::TouchEvent* event) {
  if (ProcessEvent(*event)) {
    event->SetHandled();
    event->StopPropagation();
  }
}

void TabletModeToggleFullscreenEventHandler::OnWindowDestroying(
    aura::Window* window) {
  DCHECK(drag_data_);
  DCHECK_EQ(drag_data_->window, window);
  ResetDragData();
}

bool TabletModeToggleFullscreenEventHandler::ProcessEvent(
    const ui::TouchEvent& event) {
  switch (event.type()) {
    case ui::EventType::kTouchPressed: {
      // Another drag is already underway from another finger.
      if (drag_data_) {
        return false;
      }

      aura::Window* active_window = window_util::GetActiveWindow();
      if (!active_window || !CanToggleFullscreen(active_window))
        return false;

      const int y = event.y();
      // For touch press events only process the ones on the top or bottom
      // lines.
      if (y >= kLeaveFullScreenAreaHeightInPixel &&
          y < (active_window->bounds().height() -
               kLeaveFullScreenAreaHeightInPixel)) {
        return false;
      }

      drag_data_ = DragData{.start_y_location = y, .window = active_window};
      active_window->AddObserver(this);
      return true;
    }
    case ui::EventType::kTouchReleased: {
      if (!drag_data_)
        return false;

      // Toggle fullscreen if dragged enough and the window can still be
      // fullscreened.
      const int drag_threshold =
          ShelfConfig::Get()->shelf_size() *
          ShelfConfig::Get()->drag_hide_ratio_threshold();
      if (abs(event.y() - drag_data_->start_y_location) > drag_threshold &&
          CanToggleFullscreen(drag_data_->window)) {
        WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
        WindowState::Get(drag_data_->window)->OnWMEvent(&toggle_fullscreen);
      }

      ResetDragData();
      return true;
    }
    case ui::EventType::kTouchMoved:
      return drag_data_.has_value();
    case ui::EventType::kTouchCancelled: {
      const bool drag_in_progress = drag_data_.has_value();
      ResetDragData();
      return drag_in_progress;
    }
    default:
      break;
  }

  NOTREACHED();
}

bool TabletModeToggleFullscreenEventHandler::CanToggleFullscreen(
    const aura::Window* window) {
  DCHECK(window);

  const SessionControllerImpl* controller = Shell::Get()->session_controller();
  if (controller->IsScreenLocked() ||
      controller->GetSessionState() != session_manager::SessionState::ACTIVE) {
    return false;
  }

  // Find the active window (from the primary screen) to un-fullscreen.
  aura::Window* active_window = window_util::GetActiveWindow();
  if (window != active_window)
    return false;

  const WindowState* window_state = WindowState::Get(window);
  if (!window_state->IsFullscreen() || window_state->IsInImmersiveFullscreen())
    return false;

  // Do not exit fullscreen in kiosk app mode.
  if (Shell::Get()->session_controller()->IsRunningInAppMode())
    return false;

  return true;
}

void TabletModeToggleFullscreenEventHandler::ResetDragData() {
  if (drag_data_)
    drag_data_->window->RemoveObserver(this);
  drag_data_.reset();
}

}  // namespace ash