1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
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 "components/page_info/android/page_info_controller_android.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/command_line.h"
11 #include "base/stl_util.h"
12 #include "components/content_settings/core/browser/host_content_settings_map.h"
13 #include "components/content_settings/core/common/content_settings.h"
14 #include "components/content_settings/core/common/content_settings_types.h"
15 #include "components/page_info/android/jni_headers/PageInfoController_jni.h"
16 #include "components/page_info/android/page_info_client.h"
17 #include "components/page_info/features.h"
18 #include "components/page_info/page_info.h"
19 #include "components/page_info/page_info_ui.h"
20 #include "components/security_state/core/security_state.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/content_features.h"
26 #include "content/public/common/content_switches.h"
27 #include "url/origin.h"
28
29 using base::android::ConvertUTF16ToJavaString;
30 using base::android::ConvertUTF8ToJavaString;
31 using base::android::JavaParamRef;
32
33 // static
JNI_PageInfoController_Init(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & java_web_contents)34 static jlong JNI_PageInfoController_Init(
35 JNIEnv* env,
36 const JavaParamRef<jobject>& obj,
37 const JavaParamRef<jobject>& java_web_contents) {
38 content::WebContents* web_contents =
39 content::WebContents::FromJavaWebContents(java_web_contents);
40
41 return reinterpret_cast<intptr_t>(
42 new PageInfoControllerAndroid(env, obj, web_contents));
43 }
44
PageInfoControllerAndroid(JNIEnv * env,jobject java_page_info_pop,content::WebContents * web_contents)45 PageInfoControllerAndroid::PageInfoControllerAndroid(
46 JNIEnv* env,
47 jobject java_page_info_pop,
48 content::WebContents* web_contents) {
49 // Important to use GetVisibleEntry to match what's showing in the omnibox.
50 content::NavigationEntry* nav_entry =
51 web_contents->GetController().GetVisibleEntry();
52 if (nav_entry == NULL)
53 return;
54
55 url_ = nav_entry->GetURL();
56 web_contents_ = web_contents;
57
58 controller_jobject_.Reset(env, java_page_info_pop);
59
60 page_info::PageInfoClient* page_info_client = page_info::GetPageInfoClient();
61 DCHECK(page_info_client);
62 presenter_ = std::make_unique<PageInfo>(
63 page_info_client->CreatePageInfoDelegate(web_contents), web_contents,
64 nav_entry->GetURL());
65 presenter_->InitializeUiState(this);
66 }
67
~PageInfoControllerAndroid()68 PageInfoControllerAndroid::~PageInfoControllerAndroid() {}
69
Destroy(JNIEnv * env,const JavaParamRef<jobject> & obj)70 void PageInfoControllerAndroid::Destroy(JNIEnv* env,
71 const JavaParamRef<jobject>& obj) {
72 delete this;
73 }
74
RecordPageInfoAction(JNIEnv * env,const JavaParamRef<jobject> & obj,jint action)75 void PageInfoControllerAndroid::RecordPageInfoAction(
76 JNIEnv* env,
77 const JavaParamRef<jobject>& obj,
78 jint action) {
79 presenter_->RecordPageInfoAction(
80 static_cast<PageInfo::PageInfoAction>(action));
81 }
82
UpdatePermissions(JNIEnv * env,const JavaParamRef<jobject> & obj)83 void PageInfoControllerAndroid::UpdatePermissions(
84 JNIEnv* env,
85 const JavaParamRef<jobject>& obj) {
86 presenter_->UpdatePermissions();
87 }
88
SetIdentityInfo(const IdentityInfo & identity_info)89 void PageInfoControllerAndroid::SetIdentityInfo(
90 const IdentityInfo& identity_info) {
91 JNIEnv* env = base::android::AttachCurrentThread();
92 std::unique_ptr<PageInfoUI::SecurityDescription> security_description =
93 GetSecurityDescription(identity_info);
94
95 Java_PageInfoController_setSecurityDescription(
96 env, controller_jobject_,
97 ConvertUTF16ToJavaString(env, security_description->summary),
98 ConvertUTF16ToJavaString(env, security_description->details));
99 }
100
SetCookieInfo(const CookieInfoList & cookie_info_list)101 void PageInfoControllerAndroid::SetCookieInfo(
102 const CookieInfoList& cookie_info_list) {
103 NOTIMPLEMENTED();
104 }
105
SetPageFeatureInfo(const PageFeatureInfo & info)106 void PageInfoControllerAndroid::SetPageFeatureInfo(
107 const PageFeatureInfo& info) {
108 NOTIMPLEMENTED();
109 }
110
SetPermissionInfo(const PermissionInfoList & permission_info_list,ChosenObjectInfoList chosen_object_info_list)111 void PageInfoControllerAndroid::SetPermissionInfo(
112 const PermissionInfoList& permission_info_list,
113 ChosenObjectInfoList chosen_object_info_list) {
114 JNIEnv* env = base::android::AttachCurrentThread();
115
116 // Exit without permissions if it is an internal page.
117 if (PageInfo::IsFileOrInternalPage(url_)) {
118 Java_PageInfoController_updatePermissionDisplay(env, controller_jobject_);
119 return;
120 }
121
122 // On Android, we only want to display a subset of the available options in
123 // a particular order, but only if their value is different from the
124 // default. This order comes from https://crbug.com/610358.
125 std::vector<ContentSettingsType> permissions_to_display;
126 permissions_to_display.push_back(ContentSettingsType::GEOLOCATION);
127 permissions_to_display.push_back(ContentSettingsType::MEDIASTREAM_CAMERA);
128 permissions_to_display.push_back(ContentSettingsType::MEDIASTREAM_MIC);
129 permissions_to_display.push_back(ContentSettingsType::NOTIFICATIONS);
130 permissions_to_display.push_back(ContentSettingsType::IDLE_DETECTION);
131 permissions_to_display.push_back(ContentSettingsType::IMAGES);
132 permissions_to_display.push_back(ContentSettingsType::JAVASCRIPT);
133 permissions_to_display.push_back(ContentSettingsType::POPUPS);
134 permissions_to_display.push_back(ContentSettingsType::ADS);
135 permissions_to_display.push_back(
136 ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
137 permissions_to_display.push_back(ContentSettingsType::SOUND);
138 if (base::FeatureList::IsEnabled(features::kWebNfc))
139 permissions_to_display.push_back(ContentSettingsType::NFC);
140 base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
141 if (cmd->HasSwitch(switches::kEnableExperimentalWebPlatformFeatures))
142 permissions_to_display.push_back(ContentSettingsType::BLUETOOTH_SCANNING);
143 permissions_to_display.push_back(ContentSettingsType::VR);
144 permissions_to_display.push_back(ContentSettingsType::AR);
145
146 std::map<ContentSettingsType, ContentSetting>
147 user_specified_settings_to_display;
148
149 for (const auto& permission : permission_info_list) {
150 if (base::Contains(permissions_to_display, permission.type)) {
151 base::Optional<ContentSetting> setting_to_display =
152 GetSettingToDisplay(permission);
153 if (setting_to_display) {
154 user_specified_settings_to_display[permission.type] =
155 *setting_to_display;
156 }
157 }
158 }
159
160 for (const auto& permission : permissions_to_display) {
161 if (base::Contains(user_specified_settings_to_display, permission)) {
162 base::string16 setting_title =
163 PageInfoUI::PermissionTypeToUIString(permission);
164
165 Java_PageInfoController_addPermissionSection(
166 env, controller_jobject_,
167 ConvertUTF16ToJavaString(env, setting_title),
168 static_cast<jint>(permission),
169 static_cast<jint>(user_specified_settings_to_display[permission]));
170 }
171 }
172
173 for (const auto& chosen_object : chosen_object_info_list) {
174 base::string16 object_title =
175 presenter_->GetChooserContextFromUIInfo(chosen_object->ui_info)
176 ->GetObjectDisplayName(chosen_object->chooser_object->value);
177
178 Java_PageInfoController_addPermissionSection(
179 env, controller_jobject_, ConvertUTF16ToJavaString(env, object_title),
180 static_cast<jint>(chosen_object->ui_info.content_settings_type),
181 static_cast<jint>(CONTENT_SETTING_ALLOW));
182 }
183
184 Java_PageInfoController_updatePermissionDisplay(env, controller_jobject_);
185 }
186
GetSettingToDisplay(const PageInfo::PermissionInfo & permission)187 base::Optional<ContentSetting> PageInfoControllerAndroid::GetSettingToDisplay(
188 const PageInfo::PermissionInfo& permission) {
189 // All permissions should be displayed if they are non-default.
190 if (permission.setting != CONTENT_SETTING_DEFAULT &&
191 permission.setting != permission.default_setting) {
192 return permission.setting;
193 }
194
195 // Handle exceptions for permissions which need to be displayed even if they
196 // are set to the default.
197 if (permission.type == ContentSettingsType::ADS) {
198 // The subresource filter permission should always display the default
199 // setting if it is showing up in Page Info. Logic for whether the
200 // setting should show up in Page Info is in ShouldShowPermission in
201 // page_info.cc.
202 return permission.default_setting;
203 } else if (permission.type == ContentSettingsType::JAVASCRIPT &&
204 base::FeatureList::IsEnabled(page_info::kPageInfoV2)) {
205 // The javascript content setting should show up if it is blocked globally
206 // to give users an easy way to create exceptions.
207 return permission.default_setting;
208 } else if (permission.type == ContentSettingsType::SOUND) {
209 // The sound content setting should always show up when the tab has played
210 // audio since last navigation.
211 if (web_contents_->WasEverAudible())
212 return permission.default_setting;
213 }
214
215 // TODO(crbug.com/1077766): Also return permissions that are non
216 // factory-default after we add the functionality to populate the permissions
217 // subpage directly from the permissions returned from this controller.
218
219 return base::Optional<ContentSetting>();
220 }
221