4
4
import android .util .Log ;
5
5
import android .view .KeyEvent ;
6
6
import android .view .MenuItem ;
7
- import android .widget .RadioButton ;
8
- import android .widget .RadioGroup ;
9
- import android .widget .TextView ;
10
-
11
7
import androidx .annotation .NonNull ;
12
-
13
8
import com .google .android .material .textfield .TextInputLayout ;
14
9
import com .google .common .net .InetAddresses ;
15
10
import com .google .common .net .InternetDomainName ;
16
-
17
11
import org .openobservatory .ooniprobe .R ;
18
12
import org .openobservatory .ooniprobe .common .AppLogger ;
19
13
import org .openobservatory .ooniprobe .common .PreferenceManager ;
20
14
import org .openobservatory .ooniprobe .common .ProxyProtocol ;
21
15
import org .openobservatory .ooniprobe .common .ProxySettings ;
16
+ import org .openobservatory .ooniprobe .databinding .ActivityProxyBinding ;
17
+ import ru .noties .markwon .Markwon ;
22
18
19
+ import javax .inject .Inject ;
23
20
import java .net .URISyntaxException ;
21
+ import java .util .Arrays ;
24
22
import java .util .Objects ;
25
23
26
- import javax .inject .Inject ;
27
-
28
- import ru .noties .markwon .Markwon ;
29
-
30
24
/**
31
25
* The ProxyActivity is part of the Settings. It allows users to
32
26
* configure the proxy for speaking with OONI's backends.
@@ -103,36 +97,8 @@ public class ProxyActivity extends AbstractActivity {
103
97
// The following radio group describes the top level choice
104
98
// in terms of proxying: no proxy, psiphon, or custom.
105
99
106
- // proxyRadioGroup is the top-level radio group.
107
- private RadioGroup proxyRadioGroup ;
108
-
109
- // proxyNoneRB is the radio button selecting the "none" proxy.
110
- private RadioButton proxyNoneRB ;
111
-
112
- // proxyPsiphonRB is the radio button selecting the "psiphon" proxy.
113
- private RadioButton proxyPsiphonRB ;
114
-
115
- // proxyCustomRB is the radio button for the "custom" proxy.
116
- private RadioButton proxyCustomRB ;
117
-
118
- // The following radio group allows users to choose which specific
119
- // custom proxy they would like to use. When writing this documentation,
120
- // only socks5 is available but we will add more options.
121
-
122
- // customProxyRadioGroup allows you to choose among the different
123
- // kinds of custom proxies that are available.
124
- private RadioGroup customProxyRadioGroup ;
125
-
126
- // customProxySOCKS5 selects the custom SOCKS5 proxy type.
127
- private RadioButton customProxySOCKS5 ;
128
-
129
- // The following settings allow users to configure the custom proxy.
130
-
131
- // customProxyHostname is the hostname for the custom proxy.
132
- private TextInputLayout customProxyHostname ;
100
+ ActivityProxyBinding binding ;
133
101
134
- // customProxyPort is the port for the custom proxy.
135
- private TextInputLayout customProxyPort ;
136
102
137
103
// settings contains a representation of the proxy settings
138
104
// loaded from the preference manager.
@@ -147,21 +113,13 @@ public void onCreate(Bundle savedInstanceState) {
147
113
super .onCreate (savedInstanceState );
148
114
getActivityComponent ().inject (this );
149
115
116
+ binding = ActivityProxyBinding .inflate (getLayoutInflater ());
150
117
// We draw the view and store references to objects needed
151
118
// when configuring the initial view or modifying it.
152
- setContentView (R .layout .activity_proxy );
153
- proxyRadioGroup = findViewById (R .id .proxyRadioGroup );
154
- proxyNoneRB = findViewById (R .id .proxyNone );
155
- proxyPsiphonRB = findViewById (R .id .proxyPsiphon );
156
- proxyCustomRB = findViewById (R .id .proxyCustom );
157
- customProxyRadioGroup = findViewById (R .id .customProxyRadioGroup );
158
- customProxySOCKS5 = findViewById (R .id .customProxySOCKS5 );
159
- customProxyHostname = findViewById (R .id .customProxyHostname );
160
- customProxyPort = findViewById (R .id .customProxyPort );
119
+ setContentView (binding .getRoot ());
161
120
162
121
// We fill the footer that helps users to understand this settings screen.
163
- TextView proxyFooter = findViewById (R .id .proxyFooter );
164
- Markwon .setMarkdown (proxyFooter , getString (R .string .Settings_Proxy_Footer ));
122
+ Markwon .setMarkdown (binding .proxyFooter , getString (R .string .Settings_Proxy_Footer ));
165
123
166
124
// We read settings and configure the initial view.
167
125
loadSettingsAndConfigureInitialView ();
@@ -193,11 +151,12 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
193
151
// Inspect the scheme and use the scheme to choose among the
194
152
// top-level radio buttons describing the proxy type.
195
153
if (settings .protocol == ProxyProtocol .NONE ) {
196
- proxyNoneRB .setChecked (true );
154
+ binding . proxyNone .setChecked (true );
197
155
} else if (settings .protocol == ProxyProtocol .PSIPHON ) {
198
- proxyPsiphonRB .setChecked (true );
199
- } else if (settings .protocol == ProxyProtocol .SOCKS5 ) {
200
- proxyCustomRB .setChecked (true );
156
+ binding .proxyPsiphon .setChecked (true );
157
+ } else if (Arrays .asList (getResources ().getStringArray (R .array .proxy_protocol_list )).contains (settings .protocol .getProtocol ())) {
158
+ binding .customProxyProtocol .setText (settings .protocol .getProtocol (),false );
159
+ binding .proxyCustom .setChecked (true );
201
160
} else {
202
161
// TODO(bassosimone): this should also be reported as a bug.
203
162
Log .w (TAG , "got an unhandled proxy scheme" );
@@ -208,28 +167,28 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
208
167
// If the scheme is custom, then we need to enable the
209
168
// part of the view related to custom proxies.
210
169
customProxySetEnabled (isSchemeCustom (settings .protocol ));
211
- customProxySOCKS5 .setChecked (isSchemeCustom (settings .protocol ));
212
170
213
171
// Populate all the editable fields _anyway_ so the user
214
172
// has the feeling that everything was just as before
173
+ Log .d (TAG , "(from preferences) protocol: " + settings .protocol );
174
+ logger .i (TAG , "(from preferences) protocol: " + settings .protocol );
215
175
Log .d (TAG , "(from preferences) hostname: " + settings .hostname );
216
176
logger .i (TAG , "(from preferences) hostname: " + settings .hostname );
217
177
Log .d (TAG , "(from preferences) port: " + settings .port );
218
178
logger .i (TAG , "(from preferences) port: " + settings .port );
219
- Objects .requireNonNull (customProxyHostname .getEditText ()).setText (settings .hostname );
220
- Objects .requireNonNull (customProxyPort .getEditText ()).setText (settings .port );
179
+ Objects .requireNonNull (binding . customProxyHostname .getEditText ()).setText (settings .hostname );
180
+ Objects .requireNonNull (binding . customProxyPort .getEditText ()).setText (settings .port );
221
181
222
182
// Now we need to make the top level proxy radio group interactive: when
223
183
// we change what is selected, we need the view to adapt.
224
- proxyRadioGroup .setOnCheckedChangeListener ((group , checkedId ) -> {
184
+ binding . proxyRadioGroup .setOnCheckedChangeListener ((group , checkedId ) -> {
225
185
if (checkedId == R .id .proxyNone ) {
226
186
customProxySetEnabled (false );
227
187
} else if (checkedId == R .id .proxyPsiphon ) {
228
188
customProxySetEnabled (false );
229
189
} else if (checkedId == R .id .proxyCustom ) {
230
190
customProxySetEnabled (true );
231
- customProxyRadioGroup .clearCheck ();
232
- customProxySOCKS5 .setChecked (true );
191
+ binding .customProxyRadioGroup .clearCheck ();
233
192
} else {
234
193
// TODO(bassosimone): this should also be reported as a bug.
235
194
Log .w (TAG , "unexpected state in setOnCheckedChangeListener" );
@@ -238,14 +197,14 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
238
197
});
239
198
240
199
// When we change the focus of text fields, clear any lingering error text.
241
- Objects .requireNonNull (customProxyHostname .getEditText ()).setOnFocusChangeListener ((v , hasFocus ) -> {
200
+ Objects .requireNonNull (binding . customProxyHostname .getEditText ()).setOnFocusChangeListener ((v , hasFocus ) -> {
242
201
if (!hasFocus ) {
243
- customProxyHostname .setError (null );
202
+ binding . customProxyHostname .setError (null );
244
203
}
245
204
});
246
- Objects .requireNonNull (customProxyPort .getEditText ()).setOnFocusChangeListener ((v , hasFocus ) -> {
205
+ Objects .requireNonNull (binding . customProxyPort .getEditText ()).setOnFocusChangeListener ((v , hasFocus ) -> {
247
206
if (!hasFocus ) {
248
- customProxyHostname .setError (null );
207
+ binding . customProxyHostname .setError (null );
249
208
}
250
209
});
251
210
}
@@ -254,7 +213,7 @@ private void configureInitialViewWithSettings(ProxySettings settings) {
254
213
private boolean isSchemeCustom (ProxyProtocol protocol ) {
255
214
// This is where we need to extend the implementation of we add a new scheme
256
215
// that will not be related to a custom proxy type.
257
- return protocol == ProxyProtocol .SOCKS5 ;
216
+ return protocol == ProxyProtocol .SOCKS5 || protocol == ProxyProtocol . HTTP || protocol == ProxyProtocol . HTTPS ;
258
217
}
259
218
260
219
// customProxyTextInputSetEnabled is a helper function that changes the
@@ -268,9 +227,8 @@ private void customProxyTextInputSetEnabled(@NonNull TextInputLayout input, bool
268
227
// customProxySetEnabled reacts to the enabling or disabling of the custom
269
228
// proxy group and changes the view accordingly to that.
270
229
private void customProxySetEnabled (boolean flag ) {
271
- customProxySOCKS5 .setEnabled (flag );
272
- customProxyTextInputSetEnabled (customProxyHostname , flag );
273
- customProxyTextInputSetEnabled (customProxyPort , flag );
230
+ customProxyTextInputSetEnabled (binding .customProxyHostname , flag );
231
+ customProxyTextInputSetEnabled (binding .customProxyPort , flag );
274
232
}
275
233
276
234
// isValidHostnameOrIP validates its input as an IP address or hostname.
@@ -341,14 +299,14 @@ public void onBackPressed() {
341
299
logger .i (TAG , "onBackPressed: about to save proxy settings" );
342
300
343
301
// Get the hostname and port for the custom proxy.
344
- String hostname = Objects .requireNonNull (customProxyHostname .getEditText ()).getText ().toString ();
345
- String port = Objects .requireNonNull (customProxyPort .getEditText ()).getText ().toString ();
302
+ String hostname = Objects .requireNonNull (binding . customProxyHostname .getEditText ()).getText ().toString ();
303
+ String port = Objects .requireNonNull (binding . customProxyPort .getEditText ()).getText ().toString ();
346
304
settings .hostname = hostname ;
347
305
settings .port = port ;
348
306
349
307
// If no proxy is selected then just write an empty proxy
350
308
// configuration into the settings and move on.
351
- if (proxyNoneRB .isChecked ()) {
309
+ if (binding . proxyNone .isChecked ()) {
352
310
settings .protocol = ProxyProtocol .NONE ;
353
311
saveSettings ();
354
312
super .onBackPressed ();
@@ -357,7 +315,7 @@ public void onBackPressed() {
357
315
358
316
// If the psiphon proxy is checked then write back the right
359
317
// proxy configuration for psiphon and move on.
360
- if (proxyPsiphonRB .isChecked ()) {
318
+ if (binding . proxyPsiphon .isChecked ()) {
361
319
settings .protocol = ProxyProtocol .PSIPHON ;
362
320
saveSettings ();
363
321
super .onBackPressed ();
@@ -366,26 +324,27 @@ public void onBackPressed() {
366
324
367
325
// validate the hostname for the custom proxy.
368
326
if (!isValidHostnameOrIP (hostname )) {
369
- customProxyHostname .setError ("not a valid hostname or IP" );
327
+ binding . customProxyHostname .setError ("not a valid hostname or IP" );
370
328
return ;
371
329
}
372
330
373
331
// validate the port for the custom proxy.
374
332
if (!isValidPort (port )) {
375
- customProxyPort .setError ("not a valid network port" );
333
+ binding . customProxyPort .setError ("not a valid network port" );
376
334
return ;
377
335
}
378
336
379
- // At this point we're going to assume that this is a socks5 proxy. We will
380
- // need to change the code in here when we add support for http proxies.
381
- settings . protocol = ProxyProtocol . SOCKS5 ;
337
+ // At this point we're going to assume that this is a socks5,http,https proxy.
338
+ // ProxyProtocol.valueOf will only accept one of the values in ProxyProtocol
339
+ // as in the enum definition(uppercase).
382
340
try {
341
+ settings .protocol = ProxyProtocol .valueOf (binding .customProxyProtocol .getText ().toString ().toUpperCase ());
383
342
settings .getProxyString ();
384
343
} catch (URISyntaxException e ) {
385
344
// okay, then, notwithstanding our efforts it still seems that we
386
345
// have not obtained a valid URL, so let's not proceed.
387
- customProxyHostname .setError ("cannot construct a valid URL" );
388
- customProxyPort .setError ("cannot construct a valid URL" );
346
+ binding . customProxyHostname .setError ("cannot construct a valid URL" );
347
+ binding . customProxyPort .setError ("cannot construct a valid URL" );
389
348
return ;
390
349
}
391
350
0 commit comments