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