chromium/ash/app_list/quick_app_access_model.cc

// Copyright 2023 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/app_list/quick_app_access_model.h"

#include <string>

#include "ash/app_list/app_list_controller_impl.h"
#include "ash/app_list/app_list_model_provider.h"
#include "ash/app_list/model/app_list_item.h"
#include "ash/shell.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_rep.h"

namespace ash {

QuickAppAccessModel::QuickAppAccessModel() = default;

QuickAppAccessModel::~QuickAppAccessModel() = default;

void QuickAppAccessModel::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void QuickAppAccessModel::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool QuickAppAccessModel::SetQuickApp(const std::string& app_id) {
  if (quick_app_id_ == app_id) {
    return false;
  }

  if (app_id.empty()) {
    // Remove quick app when setting a quick app with an empty app id.
    ClearQuickApp();
    UpdateQuickAppShouldShowState();
    return true;
  }

  AppListItem* item = AppListModelProvider::Get()->model()->FindItem(app_id);
  if (!item) {
    // Return and don't set the quick app id if the app item doesn't exist.
    return false;
  }

  ClearQuickApp();
  quick_app_id_ = app_id;
  item_observation_.Observe(item);

  // Request to load in the icon when the app item's icon is null.
  if (item->GetDefaultIcon().isNull()) {
    icon_load_start_time_ = base::TimeTicks::Now();
    Shell::Get()->app_list_controller()->LoadIcon(app_id);
  }

  // When quick app is already in a show state, notify that the app icon has
  // changed to cover the case where the shown quick app is changed to another
  // app.
  if (quick_app_should_show_state_) {
    for (auto& observer : observers_) {
      observer.OnQuickAppIconChanged();
    }
  }

  UpdateQuickAppShouldShowState();
  return true;
}

void QuickAppAccessModel::SetQuickAppActivated() {
  ClearQuickApp();
  UpdateQuickAppShouldShowState();
}

gfx::ImageSkia QuickAppAccessModel::GetAppIcon(gfx::Size icon_size) {
  AppListItem* item = GetQuickAppItem();

  if (!item) {
    return gfx::ImageSkia();
  }

  gfx::ImageSkia image = item->GetDefaultIcon();

  if (item->GetDefaultIcon().isNull()) {
    return gfx::ImageSkia();
  }

  image = gfx::ImageSkiaOperations::CreateResizedImage(
      image, skia::ImageOperations::RESIZE_BEST, icon_size);
  return image;
}

const std::u16string QuickAppAccessModel::GetAppName() const {
  AppListItem* item = GetQuickAppItem();
  if (!item) {
    return std::u16string();
  }
  return base::UTF8ToUTF16(item->GetDisplayName());
}

void QuickAppAccessModel::ItemDefaultIconChanged() {
  if (quick_app_should_show_state_) {
    // If quick app should already be shown, notify observers when the changed
    // icon is not null.
    if (!GetQuickAppItem()->GetDefaultIcon().isNull()) {
      for (auto& observer : observers_) {
        observer.OnQuickAppIconChanged();
      }
    }
  } else {
    if (icon_load_start_time_) {
      UmaHistogramTimes("Apps.QuickAppIconLoadTime",
                        base::TimeTicks::Now() - *icon_load_start_time_);
      icon_load_start_time_.reset();
    }
    UpdateQuickAppShouldShowState();
  }
}

void QuickAppAccessModel::ItemIconVersionChanged() {
  icon_load_start_time_ = base::TimeTicks::Now();
  Shell::Get()->app_list_controller()->LoadIcon(quick_app_id_);
}

void QuickAppAccessModel::ItemBeingDestroyed() {
  ClearQuickApp();
  UpdateQuickAppShouldShowState();
}

void QuickAppAccessModel::OnAppListVisibilityChanged(bool shown,
                                                     int64_t display_id) {
  if (shown) {
    ClearQuickApp();
    UpdateQuickAppShouldShowState();
  }
}

AppListItem* QuickAppAccessModel::GetQuickAppItem() const {
  return AppListModelProvider::Get()->model()->FindItem(quick_app_id_);
}

void QuickAppAccessModel::UpdateQuickAppShouldShowState() {
  const bool prev_should_show_quick_app = quick_app_should_show_state_;
  quick_app_should_show_state_ = ShouldShowQuickApp();

  if (prev_should_show_quick_app == quick_app_should_show_state_) {
    return;
  }

  if (!quick_app_should_show_state_) {
    app_list_controller_observer_.Reset();
  } else {
    app_list_controller_observer_.Observe(Shell::Get()->app_list_controller());
  }

  for (auto& observer : observers_) {
    observer.OnQuickAppShouldShowChanged(quick_app_should_show_state_);
  }
}

bool QuickAppAccessModel::ShouldShowQuickApp() {
  return !quick_app_id_.empty() &&
         !GetQuickAppItem()->GetDefaultIcon().isNull();
}

void QuickAppAccessModel::ClearQuickApp() {
  quick_app_id_ = "";
  item_observation_.Reset();
  icon_load_start_time_.reset();
}

}  // namespace ash