Skip to content

Commit

Permalink
Add choose file metrics
Browse files Browse the repository at this point in the history
Log an histogram with the accept and multiple attribute
an input file is clicked.

Bug: 1492557
Change-Id: I2250b027e7d099bc411ffcfb83508dcefc21fda9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4931474
Reviewed-by: Rohit Rao <rohitrao@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: Quentin Pubert <qpubert@google.com>
Cr-Commit-Position: refs/heads/main@{#1212139}
  • Loading branch information
robinolivier authored and Chromium LUCI CQ committed Oct 19, 2023
1 parent 10ea8a4 commit 04dc244
Show file tree
Hide file tree
Showing 10 changed files with 668 additions and 0 deletions.
1 change: 1 addition & 0 deletions ios/chrome/browser/web/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ source_set("web_internal") {
"//ios/chrome/browser/translate/model",
"//ios/chrome/browser/ui/infobars/coordinators",
"//ios/chrome/browser/web:feature_flags",
"//ios/chrome/browser/web/choose_file",
"//ios/chrome/browser/web/font_size",
"//ios/chrome/browser/web/image_fetch",
"//ios/chrome/browser/web/java_script_console",
Expand Down
40 changes: 40 additions & 0 deletions ios/chrome/browser/web/choose_file/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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.

import("//ios/web/public/js_messaging/optimize_ts.gni")

source_set("choose_file") {
sources = [
"choose_file_java_script_feature.h",
"choose_file_java_script_feature.mm",
]
deps = [
":choose_file_js",
"//base",
"//ios/web/public",
"//ios/web/public/js_messaging",
]
frameworks = [ "Foundation.framework" ]
}

source_set("unit_tests") {
testonly = true
sources = [ "choose_file_java_script_feature_unittest.mm" ]
deps = [
":choose_file",
"//base",
"//base/test:test_support",
"//ios/chrome/browser/shared/model/browser_state:test_support",
"//ios/web/public/test",
"//testing/gtest",
]
}

optimize_ts("choose_file_js") {
visibility = [ ":choose_file" ]

sources = [ "resources/choose_file.ts" ]

deps = [ "//ios/web/public/js_messaging:util_scripts" ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.

#ifndef IOS_CHROME_BROWSER_WEB_CHOOSE_FILE_CHOOSE_FILE_JAVA_SCRIPT_FEATURE_H_
#define IOS_CHROME_BROWSER_WEB_CHOOSE_FILE_CHOOSE_FILE_JAVA_SCRIPT_FEATURE_H_

#include "ios/web/public/js_messaging/java_script_feature.h"

// A feature which the clicks on Choose file input and logs data about it.
class ChooseFileJavaScriptFeature : public web::JavaScriptFeature {
public:
ChooseFileJavaScriptFeature();
~ChooseFileJavaScriptFeature() override;

// This feature holds no state. Thus, a single static instance
// suffices.
static ChooseFileJavaScriptFeature* GetInstance();

// JavaScriptFeature:
absl::optional<std::string> GetScriptMessageHandlerName() const override;
void ScriptMessageReceived(web::WebState* web_state,
const web::ScriptMessage& message) override;

// Logs the click on choose file input.
void LogChooseFileEvent(int accept_type, bool allow_multiple_files);
};

#endif // IOS_CHROME_BROWSER_WEB_CHOOSE_FILE_CHOOSE_FILE_JAVA_SCRIPT_FEATURE_H_
152 changes: 152 additions & 0 deletions ios/chrome/browser/web/choose_file/choose_file_java_script_feature.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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.

#import "ios/chrome/browser/web/choose_file/choose_file_java_script_feature.h"

#import "base/logging.h"
#import "base/metrics/histogram_functions.h"
#import "base/no_destructor.h"
#import "ios/web/public/js_messaging/script_message.h"

namespace {
const char kChooseFileScript[] = "choose_file";
const char kChooseFileScriptName[] = "ChooseFileHandler";

// The type of attributes of the input element.
// This enum is persisted in log, do not reorder or reuse buckets.
// Used in IOSWebFileInputAttributes enum for IOS.Web.FileInput.Clicked.
enum class ChooseFileAccept {
kNoAccept = 0,
kNoAcceptMultiple = 1,
kMixedAccept = 2,
kMixedAcceptMultiple = 3,
kUnknownAccept = 4,
kUnknownAcceptMultiple = 5,
kImageAccept = 6,
kImageAcceptMultiple = 7,
kVideoAccept = 8,
kVideoAcceptMultiple = 9,
kAudioAccept = 10,
kAudioAcceptMultiple = 11,
kArchiveAccept = 12,
kArchiveAcceptMultiple = 13,
kPDFAccept = 14,
kPDFAcceptMultiple = 15,
kDocAccept = 16,
kDocAcceptMultiple = 17,
kAppleAccept = 18,
kAppleAcceptMultiple = 19,
kMaxValue = kAppleAcceptMultiple,
};

// The UMA bucket for `accept_type` and `allow_multiple_files`.
// See AcceptType enumeration in
// ios/chrome/browser/web/choose_file/resources/choose_file.ts
ChooseFileAccept BucketForChooseFileEvent(int accept_type,
bool allow_multiple_files) {
if (allow_multiple_files) {
switch (accept_type) {
case 0:
return ChooseFileAccept::kNoAcceptMultiple;
case 1:
return ChooseFileAccept::kMixedAcceptMultiple;
case 2:
return ChooseFileAccept::kUnknownAcceptMultiple;
case 3:
return ChooseFileAccept::kImageAcceptMultiple;
case 4:
return ChooseFileAccept::kVideoAcceptMultiple;
case 5:
return ChooseFileAccept::kAudioAcceptMultiple;
case 6:
return ChooseFileAccept::kArchiveAcceptMultiple;
case 7:
return ChooseFileAccept::kPDFAcceptMultiple;
case 8:
return ChooseFileAccept::kDocAcceptMultiple;
case 9:
return ChooseFileAccept::kAppleAcceptMultiple;
default:
NOTREACHED_NORETURN();
}
}
switch (accept_type) {
case 0:
return ChooseFileAccept::kNoAccept;
case 1:
return ChooseFileAccept::kMixedAccept;
case 2:
return ChooseFileAccept::kUnknownAccept;
case 3:
return ChooseFileAccept::kImageAccept;
case 4:
return ChooseFileAccept::kVideoAccept;
case 5:
return ChooseFileAccept::kAudioAccept;
case 6:
return ChooseFileAccept::kArchiveAccept;
case 7:
return ChooseFileAccept::kPDFAccept;
case 8:
return ChooseFileAccept::kDocAccept;
case 9:
return ChooseFileAccept::kAppleAccept;
default:
NOTREACHED_NORETURN();
}
}
} // namespace

ChooseFileJavaScriptFeature::ChooseFileJavaScriptFeature()
: JavaScriptFeature(web::ContentWorld::kIsolatedWorld,
{FeatureScript::CreateWithFilename(
kChooseFileScript,
FeatureScript::InjectionTime::kDocumentEnd,
FeatureScript::TargetFrames::kAllFrames)}) {}

ChooseFileJavaScriptFeature::~ChooseFileJavaScriptFeature() = default;

ChooseFileJavaScriptFeature* ChooseFileJavaScriptFeature::GetInstance() {
static base::NoDestructor<ChooseFileJavaScriptFeature> instance;
return instance.get();
}

absl::optional<std::string>
ChooseFileJavaScriptFeature::GetScriptMessageHandlerName() const {
return kChooseFileScriptName;
}

void ChooseFileJavaScriptFeature::ScriptMessageReceived(
web::WebState* web_state,
const web::ScriptMessage& message) {
DCHECK(web_state);

// Verify that the message is well-formed before using it
if (!message.body()->is_dict()) {
return;
}
base::Value::Dict& body_dict = message.body()->GetDict();

absl::optional<double> accept_type = body_dict.FindDouble("acceptType");
absl::optional<bool> has_multiple = body_dict.FindBool("hasMultiple");
if (!accept_type || !has_multiple) {
return;
}
int accept_type_int = static_cast<int>(*accept_type);
// See AcceptType enumeration in
// ios/chrome/browser/web/choose_file/resources/choose_file.ts
if (accept_type_int < 0 || accept_type_int > 9) {
return;
}

LogChooseFileEvent(accept_type_int, *has_multiple);
}

void ChooseFileJavaScriptFeature::LogChooseFileEvent(
int accept_type,
bool allow_multiple_files) {
base::UmaHistogramEnumeration(
"IOS.Web.FileInput.Clicked",
BucketForChooseFileEvent(accept_type, allow_multiple_files));
}

0 comments on commit 04dc244

Please sign in to comment.