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