910e62b5创建于 1月15日历史提交
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/app_restore/app_restore_utils.h"

#include "base/functional/bind.h"
#include "base/strings/string_number_conversions.h"
#include "chromeos/ui/base/app_types.h"
#include "chromeos/ui/base/window_properties.h"
#include "components/app_constants/constants.h"
#include "components/app_restore/app_restore_info.h"
#include "components/app_restore/desk_template_read_handler.h"
#include "components/app_restore/features.h"
#include "components/app_restore/full_restore_read_handler.h"
#include "components/app_restore/full_restore_save_handler.h"
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/views/widget/widget_delegate.h"

namespace app_restore {
namespace {

const char kCrxAppPrefix[] = "_crx_";

static int32_t session_id_counter = kArcSessionIdOffsetForRestoredLaunching;

}  // namespace

bool IsArcWindow(aura::Window* window) {
  return window->GetProperty(chromeos::kAppTypeKey) ==
         chromeos::AppType::ARC_APP;
}

bool HasWindowInfo(int32_t restore_window_id) {
  // DeskTemplateReadHandler::GetWindowInfo returns nullptr if
  // `restore_window_id` is unknown.
  if (DeskTemplateReadHandler::Get()->GetWindowInfo(restore_window_id))
    return true;
  return full_restore::FullRestoreReadHandler::GetInstance()->HasWindowInfo(
      restore_window_id);
}

void ApplyProperties(app_restore::WindowInfo* window_info,
                     ui::PropertyHandler* property_handler) {
  DCHECK(window_info);
  DCHECK(property_handler);

  property_handler->SetProperty(app_restore::kWindowInfoKey,
                                new WindowInfo(*window_info));

  if (window_info->activation_index) {
    const int32_t index = *window_info->activation_index;
    // kActivationIndexKey is owned, which allows for passing in this raw
    // pointer.
    property_handler->SetProperty(app_restore::kActivationIndexKey,
                                  std::make_unique<int32_t>(index));
    // Windows opened from full restore should not be activated. Widgets that
    // are shown are activated by default. Force the widget to not be
    // activatable; the activation will be restored in ash once the window is
    // launched.
    property_handler->SetProperty(app_restore::kLaunchedFromAppRestoreKey,
                                  true);
  }
  if (window_info->pre_minimized_show_state_type) {
    property_handler->SetProperty(aura::client::kRestoreShowStateKey,
                                  *window_info->pre_minimized_show_state_type);
  }
}

void ModifyWidgetParams(int32_t restore_window_id,
                        views::Widget::InitParams* out_params) {
  DCHECK(out_params);

  const bool is_arc_app =
      out_params->init_properties_container.GetProperty(
          chromeos::kAppTypeKey) == chromeos::AppType::ARC_APP;
  std::unique_ptr<app_restore::WindowInfo> window_info;
  auto* full_restore_read_handler =
      full_restore::FullRestoreReadHandler::GetInstance();
  auto* desk_template_read_handler = DeskTemplateReadHandler::Get();
  if (is_arc_app) {
    // This will return nullptr if `restore_window_id` doesn't belong to a desk
    // template launch. In that case, we fall back on full restore.
    ArcReadHandler* arc_read_handler =
        desk_template_read_handler->GetArcReadHandlerForWindow(
            restore_window_id);
    if (!arc_read_handler)
      arc_read_handler = full_restore_read_handler->arc_read_handler();

    window_info = arc_read_handler
                      ? arc_read_handler->GetWindowInfo(restore_window_id)
                      : nullptr;
  } else {
    window_info = desk_template_read_handler->GetWindowInfo(restore_window_id);
    if (!window_info) {
      window_info = full_restore_read_handler->GetWindowInfoForActiveProfile(
          restore_window_id);
    }
  }
  if (!window_info)
    return;

  ApplyProperties(window_info.get(), &out_params->init_properties_container);

  if (window_info->desk_id) {
    out_params->workspace = base::NumberToString(*window_info->desk_id);
  } else if (window_info->desk_guid.is_valid()) {
    out_params->workspace = window_info->desk_guid.AsLowercaseString();
  }
  if (window_info->current_bounds)
    out_params->bounds = *window_info->current_bounds;
  if (window_info->window_state_type) {
    // ToWindowShowState will make us lose some ash-specific types (left/right
    // snap). Ash is responsible for restoring these states by checking
    // GetWindowInfo.
    out_params->show_state =
        chromeos::ToWindowShowState(*window_info->window_state_type);
  }

  // Register to track when the widget has initialized. If a delegate is not
  // set, then the widget creator is responsible for calling
  // OnWidgetInitialized.
  views::WidgetDelegate* delegate = out_params->delegate;
  if (delegate) {
    delegate->RegisterWidgetInitializedCallback(base::BindOnce(
        [](views::WidgetDelegate* delegate) {
          app_restore::AppRestoreInfo::GetInstance()->OnWidgetInitialized(
              delegate->GetWidget());
        },
        delegate));
  }
}

int32_t FetchRestoreWindowId(const std::string& app_id) {
  // If full restore is running and full restore knows the app_id, then we use
  // it. Otherwise fall back on desk templates.
  auto* full_restore_read_handler =
      full_restore::FullRestoreReadHandler::GetInstance();

  int32_t restore_window_id = 0;
  if (full_restore_read_handler->IsFullRestoreRunning())
    restore_window_id = full_restore_read_handler->FetchRestoreWindowId(app_id);

  if (!restore_window_id) {
    restore_window_id =
        DeskTemplateReadHandler::Get()->FetchRestoreWindowId(app_id);
  }

  return restore_window_id;
}

int32_t CreateArcSessionId() {
  // ARC session id offset start counting from a large number. When the counter
  // overflow, it will less the start number.
  if (session_id_counter < kArcSessionIdOffsetForRestoredLaunching) {
    LOG(WARNING) << "ARC session id is overflow: " << session_id_counter;
    session_id_counter = kArcSessionIdOffsetForRestoredLaunching;
  }
  return ++session_id_counter;
}

void SetArcSessionIdForWindowId(int32_t arc_session_id, int32_t window_id) {
  auto* desk_template_read_handler = DeskTemplateReadHandler::Get();
  if (desk_template_read_handler->IsKnownArcSessionId(arc_session_id)) {
    desk_template_read_handler->SetArcSessionIdForWindowId(arc_session_id,
                                                           window_id);
  } else {
    full_restore::FullRestoreReadHandler::GetInstance()
        ->SetArcSessionIdForWindowId(arc_session_id, window_id);
  }
}

void SetDeskTemplateLaunchIdForArcSessionId(int32_t arc_session_id,
                                            int32_t desk_template_launch_id) {
  DeskTemplateReadHandler::Get()->SetLaunchIdForArcSessionId(
      arc_session_id, desk_template_launch_id);
}

int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id) {
  if (int32_t restore_window_id =
          DeskTemplateReadHandler::Get()->GetArcRestoreWindowIdForTaskId(
              task_id)) {
    return restore_window_id;
  }
  return full_restore::FullRestoreReadHandler::GetInstance()
      ->GetArcRestoreWindowIdForTaskId(task_id);
}

int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id) {
  if (int32_t restore_window_id =
          DeskTemplateReadHandler::Get()->GetArcRestoreWindowIdForSessionId(
              session_id)) {
    return restore_window_id;
  }
  return full_restore::FullRestoreReadHandler::GetInstance()
      ->GetArcRestoreWindowIdForSessionId(session_id);
}

std::string GetAppIdFromAppName(const std::string& app_name) {
  std::string prefix(kCrxAppPrefix);
  if (app_name.substr(0, prefix.length()) != prefix)
    return std::string();
  return app_name.substr(prefix.length());
}

std::tuple<int, int, int> GetWindowAndTabCount(
    const RestoreData& restore_data) {
  int window_count = 0;
  int tab_count = 0;
  int total_count = 0;

  const RestoreData::AppIdToLaunchList& launch_list_map =
      restore_data.app_id_to_launch_list();
  for (const auto& [app_id, launch_list] : launch_list_map) {
    for (const auto& [window_id, app_restore_data] : launch_list) {
      const std::vector<GURL>& urls = app_restore_data->browser_extra_info.urls;
      // Url field could be empty if the app is not the browser, or if from full
      // restore. We check the app type also in case the url field is not set up
      // correctly.
      if (urls.empty() || app_id != app_constants::kChromeAppId) {
        ++window_count;
        ++total_count;
        continue;
      }

      ++window_count;
      tab_count += urls.size();
      total_count += urls.size();
    }
  }

  return std::make_tuple(window_count, tab_count, total_count);
}

}  // namespace app_restore