1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/android/input_hint_checker.h"
6
7 #include "base/base_jni/InputHintChecker_jni.h"
8 #include "base/feature_list.h"
9 #include "base/metrics/field_trial_params.h"
10 #include "base/no_destructor.h"
11 #include "base/time/time.h"
12
13 namespace base::android {
14
15 namespace {
16
17 bool g_input_hint_enabled;
18 base::TimeDelta g_poll_interval;
19 InputHintChecker* g_test_instance;
20
21 } // namespace
22
23 // Whether to fetch the input hint from the system. When disabled, pretends
24 // that no input is ever queued.
25 BASE_EXPORT
26 BASE_FEATURE(kYieldWithInputHint,
27 "YieldWithInputHint",
28 base::FEATURE_DISABLED_BY_DEFAULT);
29
30 // Min time delta between checks for the input hint. Must be a smaller than
31 // time to produce a frame, but a bit longer than the time it takes to retrieve
32 // the hint.
33 const base::FeatureParam<int> kPollIntervalMillisParam{&kYieldWithInputHint,
34 "poll_interval_ms", 3};
35
36 // static
InitializeFeatures()37 void InputHintChecker::InitializeFeatures() {
38 bool is_enabled = base::FeatureList::IsEnabled(kYieldWithInputHint);
39 g_input_hint_enabled = is_enabled;
40 if (is_enabled) {
41 g_poll_interval = Milliseconds(kPollIntervalMillisParam.Get());
42 }
43 }
44
HasInputImplWithThrottling()45 bool InputHintChecker::HasInputImplWithThrottling() {
46 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
47 auto now = base::TimeTicks::Now();
48 if (last_checked_.is_null() || (now - last_checked_) >= g_poll_interval) {
49 last_checked_ = now;
50 // TODO(pasko): Implement fetching the hint from the system.
51 return false;
52 }
53 return false;
54 }
55
SetView(JNIEnv * env,jobject root_view)56 void InputHintChecker::SetView(JNIEnv* env, jobject root_view) {
57 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
58 view_ = JavaObjectWeakGlobalRef(env, root_view);
59 }
60
61 // static
HasInput()62 bool InputHintChecker::HasInput() {
63 if (!g_input_hint_enabled) {
64 return false;
65 }
66 return GetInstance().HasInputImplWithThrottling();
67 }
68
GetInstance()69 InputHintChecker& InputHintChecker::GetInstance() {
70 static NoDestructor<InputHintChecker> checker;
71 if (g_test_instance) {
72 return *g_test_instance;
73 }
74 return *checker.get();
75 }
76
ScopedOverrideInstance(InputHintChecker * checker)77 InputHintChecker::ScopedOverrideInstance::ScopedOverrideInstance(
78 InputHintChecker* checker) {
79 g_test_instance = checker;
80 }
81
~ScopedOverrideInstance()82 InputHintChecker::ScopedOverrideInstance::~ScopedOverrideInstance() {
83 g_test_instance = nullptr;
84 }
85
JNI_InputHintChecker_SetView(_JNIEnv * env,const JavaParamRef<jobject> & v)86 void JNI_InputHintChecker_SetView(_JNIEnv* env,
87 const JavaParamRef<jobject>& v) {
88 InputHintChecker::GetInstance().SetView(env, v.obj());
89 }
90
91 } // namespace base::android
92