blob: b2cdee61c51a84db75819acd779001a45958dc8f [file] [log] [blame]
// Copyright 2016 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.
#ifndef CHROME_BROWSER_CHROMEOS_ARC_INTENT_HELPER_ARC_NAVIGATION_THROTTLE_H_
#define CHROME_BROWSER_CHROMEOS_ARC_INTENT_HELPER_ARC_NAVIGATION_THROTTLE_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/arc/intent_helper/activity_icon_loader.h"
#include "content/public/browser/navigation_throttle.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
namespace content {
class NavigationHandle;
class WebContents;
} // namespace content
namespace arc {
// A class that allow us to retrieve ARC app's information and handle URL
// traffic initiated on Chrome browser, either on Chrome or an ARC's app.
class ArcNavigationThrottle : public content::NavigationThrottle {
public:
// These enums are used to define the buckets for an enumerated UMA histogram
// and need to be synced with histograms.xml. This enum class should also be
// treated as append-only.
enum class CloseReason : int {
ERROR = 0,
DIALOG_DEACTIVATED = 1,
ALWAYS_PRESSED = 2,
JUST_ONCE_PRESSED = 3,
PREFERRED_ACTIVITY_FOUND = 4,
SIZE,
INVALID = SIZE,
};
// As for CloseReason, these define the buckets for an UMA histogram, so this
// must be treated in an append-only fashion. This helps especify where a
// navigation will continue.
enum class Platform : int {
ARC = 0,
CHROME = 1,
SIZE,
};
// Restricts the amount of apps displayed to the user without the need of a
// ScrollView.
enum { kMaxAppResults = 3 };
struct AppInfo {
AppInfo(gfx::Image img, std::string package, std::string activity)
: icon(img), package_name(package), activity_name(activity) {}
gfx::Image icon;
std::string package_name;
std::string activity_name;
};
using ShowIntentPickerCallback = base::Callback<void(
content::WebContents* web_contents,
const std::vector<AppInfo>& app_info,
const base::Callback<void(const std::string&, CloseReason)>& cb)>;
ArcNavigationThrottle(content::NavigationHandle* navigation_handle,
const ShowIntentPickerCallback& show_intent_picker_cb);
~ArcNavigationThrottle() override;
static bool ShouldOverrideUrlLoadingForTesting(const GURL& previous_url,
const GURL& current_url);
// Finds |selected_app_package| from the |handlers| array and returns the
// index. If the app is not found, returns |handlers.size()|.
static size_t GetAppIndex(
const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
const std::string& selected_app_package);
// Determines the destination of the current navigation. We know that if the
// |close_reason| is either ERROR or DIALOG_DEACTIVATED the navigation MUST
// stay in Chrome, otherwise we can assume the navigation goes to ARC with the
// exception of the |selected_app_package| being Chrome.
static Platform GetDestinationPlatform(
const std::string& selected_app_package,
CloseReason close_reason);
// Records intent picker usage statistics as well as whether navigations are
// continued or redirected to Chrome or ARC respectively, via UMA histograms.
static void RecordUma(CloseReason close_reason, Platform platform);
// Swaps Chrome app with any app in row |kMaxAppResults-1| iff its index is
// bigger, thus ensuring the user can always see Chrome without scrolling.
// When swap is needed, fills |out_indices| and returns true. If |handlers|
// do not have Chrome, returns false.
static bool IsSwapElementsNeeded(
const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
std::pair<size_t, size_t>* out_indices);
static bool IsAppAvailableForTesting(
const std::vector<mojom::IntentHandlerInfoPtr>& handlers);
static size_t FindPreferredAppForTesting(
const std::vector<mojom::IntentHandlerInfoPtr>& handlers);
private:
// content::Navigation implementation:
NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;
NavigationThrottle::ThrottleCheckResult HandleRequest();
void OnAppCandidatesReceived(
std::vector<mojom::IntentHandlerInfoPtr> handlers);
void OnAppIconsReceived(
std::vector<mojom::IntentHandlerInfoPtr> handlers,
std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons);
void OnIntentPickerClosed(std::vector<mojom::IntentHandlerInfoPtr> handlers,
const std::string& selected_app_package,
CloseReason close_reason);
GURL GetStartingGURL() const;
// A callback object that allow us to display an IntentPicker when Run() is
// executed, it also allow us to report the user's selection back to
// OnIntentPickerClosed().
ShowIntentPickerCallback show_intent_picker_callback_;
// A cache of the action the user took the last time this navigation throttle
// popped up the intent picker dialog. If the dialog has never been popped up
// before, this will have a value of CloseReason::INVALID. Used to avoid
// popping up the dialog multiple times on chains of multiple redirects.
CloseReason previous_user_action_;
// Keeps a referrence to the starting GURL.
GURL starting_gurl_;
// This has to be the last member of the class.
base::WeakPtrFactory<ArcNavigationThrottle> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcNavigationThrottle);
};
} // namespace arc
#endif // CHROME_BROWSER_CHROMEOS_ARC_INTENT_HELPER_ARC_NAVIGATION_THROTTLE_H_