1 // Copyright 2016 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 "chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "base/android/jni_android.h"
13 #include "base/android/jni_string.h"
14 #include "base/bind.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/android/chrome_jni_headers/UsbChooserDialog_jni.h"
17 #include "chrome/browser/ssl/security_state_tab_helper.h"
18 #include "chrome/browser/vr/vr_tab_helper.h"
19 #include "chrome/common/url_constants.h"
20 #include "components/security_state/core/security_state.h"
21 #include "components/url_formatter/elide_url.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "device/vr/buildflags/buildflags.h"
25 #include "ui/android/window_android.h"
26 #include "url/gurl.h"
27 
28 // static
Create(content::RenderFrameHost * render_frame_host,std::unique_ptr<ChooserController> controller,base::OnceClosure on_close)29 std::unique_ptr<UsbChooserDialogAndroid> UsbChooserDialogAndroid::Create(
30     content::RenderFrameHost* render_frame_host,
31     std::unique_ptr<ChooserController> controller,
32     base::OnceClosure on_close) {
33   content::WebContents* web_contents =
34       content::WebContents::FromRenderFrameHost(render_frame_host);
35 
36   // TODO(asimjour): This should be removed once we have proper
37   // implementation of USB chooser in VR.
38   if (vr::VrTabHelper::IsUiSuppressedInVr(
39           web_contents, vr::UiSuppressedElement::kUsbChooser)) {
40     return nullptr;
41   }
42 
43   // Create (and show) the UsbChooser dialog.
44   base::android::ScopedJavaLocalRef<jobject> window_android =
45       web_contents->GetNativeView()->GetWindowAndroid()->GetJavaObject();
46   JNIEnv* env = base::android::AttachCurrentThread();
47   base::android::ScopedJavaLocalRef<jstring> origin_string =
48       base::android::ConvertUTF16ToJavaString(
49           env, url_formatter::FormatOriginForSecurityDisplay(
50                    render_frame_host->GetLastCommittedOrigin()));
51   SecurityStateTabHelper* helper =
52       SecurityStateTabHelper::FromWebContents(web_contents);
53   DCHECK(helper);
54 
55   auto dialog = std::make_unique<UsbChooserDialogAndroid>(std::move(controller),
56                                                           std::move(on_close));
57   dialog->java_dialog_.Reset(Java_UsbChooserDialog_create(
58       env, window_android, origin_string, helper->GetSecurityLevel(),
59       reinterpret_cast<intptr_t>(dialog.get())));
60   if (dialog->java_dialog_.is_null())
61     return nullptr;
62 
63   return dialog;
64 }
65 
UsbChooserDialogAndroid(std::unique_ptr<ChooserController> controller,base::OnceClosure on_close)66 UsbChooserDialogAndroid::UsbChooserDialogAndroid(
67     std::unique_ptr<ChooserController> controller,
68     base::OnceClosure on_close)
69     : controller_(std::move(controller)), on_close_(std::move(on_close)) {
70   controller_->set_view(this);
71 }
72 
~UsbChooserDialogAndroid()73 UsbChooserDialogAndroid::~UsbChooserDialogAndroid() {
74   if (!java_dialog_.is_null()) {
75     Java_UsbChooserDialog_closeDialog(base::android::AttachCurrentThread(),
76                                       java_dialog_);
77   }
78   controller_->set_view(nullptr);
79 }
80 
OnOptionsInitialized()81 void UsbChooserDialogAndroid::OnOptionsInitialized() {
82   for (size_t i = 0; i < controller_->NumOptions(); ++i)
83     OnOptionAdded(i);
84 
85   JNIEnv* env = base::android::AttachCurrentThread();
86   Java_UsbChooserDialog_setIdleState(env, java_dialog_);
87 }
88 
OnOptionAdded(size_t index)89 void UsbChooserDialogAndroid::OnOptionAdded(size_t index) {
90   JNIEnv* env = base::android::AttachCurrentThread();
91 
92   DCHECK_LE(index, item_id_map_.size());
93   int item_id = next_item_id_++;
94   std::string item_id_str = base::NumberToString(item_id);
95   item_id_map_.insert(item_id_map_.begin() + index, item_id_str);
96 
97   base::string16 device_name = controller_->GetOption(index);
98   Java_UsbChooserDialog_addDevice(
99       env, java_dialog_,
100       base::android::ConvertUTF8ToJavaString(env, item_id_str),
101       base::android::ConvertUTF16ToJavaString(env, device_name));
102 }
103 
OnOptionRemoved(size_t index)104 void UsbChooserDialogAndroid::OnOptionRemoved(size_t index) {
105   JNIEnv* env = base::android::AttachCurrentThread();
106 
107   DCHECK_LT(index, item_id_map_.size());
108   std::string item_id = item_id_map_[index];
109   item_id_map_.erase(item_id_map_.begin() + index);
110 
111   Java_UsbChooserDialog_removeDevice(
112       env, java_dialog_, base::android::ConvertUTF8ToJavaString(env, item_id));
113 }
114 
OnOptionUpdated(size_t index)115 void UsbChooserDialogAndroid::OnOptionUpdated(size_t index) {
116   NOTREACHED();
117 }
118 
OnAdapterEnabledChanged(bool enabled)119 void UsbChooserDialogAndroid::OnAdapterEnabledChanged(bool enabled) {
120   NOTREACHED();
121 }
122 
OnRefreshStateChanged(bool refreshing)123 void UsbChooserDialogAndroid::OnRefreshStateChanged(bool refreshing) {
124   NOTREACHED();
125 }
126 
OnItemSelected(JNIEnv * env,const base::android::JavaParamRef<jstring> & item_id_jstring)127 void UsbChooserDialogAndroid::OnItemSelected(
128     JNIEnv* env,
129     const base::android::JavaParamRef<jstring>& item_id_jstring) {
130   std::string item_id =
131       base::android::ConvertJavaStringToUTF8(env, item_id_jstring);
132   auto it = std::find(item_id_map_.begin(), item_id_map_.end(), item_id);
133   DCHECK(it != item_id_map_.end());
134   controller_->Select({std::distance(item_id_map_.begin(), it)});
135   std::move(on_close_).Run();
136 }
137 
OnDialogCancelled(JNIEnv * env)138 void UsbChooserDialogAndroid::OnDialogCancelled(JNIEnv* env) {
139   Cancel();
140 }
141 
LoadUsbHelpPage(JNIEnv * env)142 void UsbChooserDialogAndroid::LoadUsbHelpPage(JNIEnv* env) {
143   controller_->OpenHelpCenterUrl();
144   Cancel();
145 }
146 
Cancel()147 void UsbChooserDialogAndroid::Cancel() {
148   controller_->Cancel();
149   std::move(on_close_).Run();
150 }
151