• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.appspot.apprtc;
12 
13 import android.annotation.TargetApi;
14 import android.app.Activity;
15 import android.app.AlertDialog;
16 import android.content.DialogInterface;
17 import android.content.Intent;
18 import android.content.SharedPreferences;
19 import android.content.pm.PackageInfo;
20 import android.content.pm.PackageManager;
21 import android.net.Uri;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.preference.PreferenceManager;
25 import android.support.annotation.Nullable;
26 import android.util.Log;
27 import android.view.ContextMenu;
28 import android.view.KeyEvent;
29 import android.view.Menu;
30 import android.view.MenuItem;
31 import android.view.View;
32 import android.view.View.OnClickListener;
33 import android.view.inputmethod.EditorInfo;
34 import android.webkit.URLUtil;
35 import android.widget.AdapterView;
36 import android.widget.ArrayAdapter;
37 import android.widget.EditText;
38 import android.widget.ImageButton;
39 import android.widget.ListView;
40 import android.widget.TextView;
41 import java.util.ArrayList;
42 import java.util.Random;
43 import org.json.JSONArray;
44 import org.json.JSONException;
45 
46 /**
47  * Handles the initial setup where the user selects which room to join.
48  */
49 public class ConnectActivity extends Activity {
50   private static final String TAG = "ConnectActivity";
51   private static final int CONNECTION_REQUEST = 1;
52   private static final int PERMISSION_REQUEST = 2;
53   private static final int REMOVE_FAVORITE_INDEX = 0;
54   private static boolean commandLineRun;
55 
56   private ImageButton addFavoriteButton;
57   private EditText roomEditText;
58   private ListView roomListView;
59   private SharedPreferences sharedPref;
60   private String keyprefResolution;
61   private String keyprefFps;
62   private String keyprefVideoBitrateType;
63   private String keyprefVideoBitrateValue;
64   private String keyprefAudioBitrateType;
65   private String keyprefAudioBitrateValue;
66   private String keyprefRoomServerUrl;
67   private String keyprefRoom;
68   private String keyprefRoomList;
69   private ArrayList<String> roomList;
70   private ArrayAdapter<String> adapter;
71 
72   @Override
onCreate(Bundle savedInstanceState)73   public void onCreate(Bundle savedInstanceState) {
74     super.onCreate(savedInstanceState);
75 
76     // Get setting keys.
77     PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
78     sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
79     keyprefResolution = getString(R.string.pref_resolution_key);
80     keyprefFps = getString(R.string.pref_fps_key);
81     keyprefVideoBitrateType = getString(R.string.pref_maxvideobitrate_key);
82     keyprefVideoBitrateValue = getString(R.string.pref_maxvideobitratevalue_key);
83     keyprefAudioBitrateType = getString(R.string.pref_startaudiobitrate_key);
84     keyprefAudioBitrateValue = getString(R.string.pref_startaudiobitratevalue_key);
85     keyprefRoomServerUrl = getString(R.string.pref_room_server_url_key);
86     keyprefRoom = getString(R.string.pref_room_key);
87     keyprefRoomList = getString(R.string.pref_room_list_key);
88 
89     setContentView(R.layout.activity_connect);
90 
91     roomEditText = findViewById(R.id.room_edittext);
92     roomEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
93       @Override
94       public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
95         if (i == EditorInfo.IME_ACTION_DONE) {
96           addFavoriteButton.performClick();
97           return true;
98         }
99         return false;
100       }
101     });
102     roomEditText.requestFocus();
103 
104     roomListView = findViewById(R.id.room_listview);
105     roomListView.setEmptyView(findViewById(android.R.id.empty));
106     roomListView.setOnItemClickListener(roomListClickListener);
107     registerForContextMenu(roomListView);
108     ImageButton connectButton = findViewById(R.id.connect_button);
109     connectButton.setOnClickListener(connectListener);
110     addFavoriteButton = findViewById(R.id.add_favorite_button);
111     addFavoriteButton.setOnClickListener(addFavoriteListener);
112 
113     requestPermissions();
114   }
115 
116   @Override
onCreateOptionsMenu(Menu menu)117   public boolean onCreateOptionsMenu(Menu menu) {
118     getMenuInflater().inflate(R.menu.connect_menu, menu);
119     return true;
120   }
121 
122   @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)123   public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
124     if (v.getId() == R.id.room_listview) {
125       AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
126       menu.setHeaderTitle(roomList.get(info.position));
127       String[] menuItems = getResources().getStringArray(R.array.roomListContextMenu);
128       for (int i = 0; i < menuItems.length; i++) {
129         menu.add(Menu.NONE, i, i, menuItems[i]);
130       }
131     } else {
132       super.onCreateContextMenu(menu, v, menuInfo);
133     }
134   }
135 
136   @Override
onContextItemSelected(MenuItem item)137   public boolean onContextItemSelected(MenuItem item) {
138     if (item.getItemId() == REMOVE_FAVORITE_INDEX) {
139       AdapterView.AdapterContextMenuInfo info =
140           (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
141       roomList.remove(info.position);
142       adapter.notifyDataSetChanged();
143       return true;
144     }
145 
146     return super.onContextItemSelected(item);
147   }
148 
149   @Override
onOptionsItemSelected(MenuItem item)150   public boolean onOptionsItemSelected(MenuItem item) {
151     // Handle presses on the action bar items.
152     if (item.getItemId() == R.id.action_settings) {
153       Intent intent = new Intent(this, SettingsActivity.class);
154       startActivity(intent);
155       return true;
156     } else if (item.getItemId() == R.id.action_loopback) {
157       connectToRoom(null, false, true, false, 0);
158       return true;
159     } else {
160       return super.onOptionsItemSelected(item);
161     }
162   }
163 
164   @Override
onPause()165   public void onPause() {
166     super.onPause();
167     String room = roomEditText.getText().toString();
168     String roomListJson = new JSONArray(roomList).toString();
169     SharedPreferences.Editor editor = sharedPref.edit();
170     editor.putString(keyprefRoom, room);
171     editor.putString(keyprefRoomList, roomListJson);
172     editor.commit();
173   }
174 
175   @Override
onResume()176   public void onResume() {
177     super.onResume();
178     String room = sharedPref.getString(keyprefRoom, "");
179     roomEditText.setText(room);
180     roomList = new ArrayList<>();
181     String roomListJson = sharedPref.getString(keyprefRoomList, null);
182     if (roomListJson != null) {
183       try {
184         JSONArray jsonArray = new JSONArray(roomListJson);
185         for (int i = 0; i < jsonArray.length(); i++) {
186           roomList.add(jsonArray.get(i).toString());
187         }
188       } catch (JSONException e) {
189         Log.e(TAG, "Failed to load room list: " + e.toString());
190       }
191     }
192     adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, roomList);
193     roomListView.setAdapter(adapter);
194     if (adapter.getCount() > 0) {
195       roomListView.requestFocus();
196       roomListView.setItemChecked(0, true);
197     }
198   }
199 
200   @Override
onActivityResult(int requestCode, int resultCode, Intent data)201   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
202     if (requestCode == CONNECTION_REQUEST && commandLineRun) {
203       Log.d(TAG, "Return: " + resultCode);
204       setResult(resultCode);
205       commandLineRun = false;
206       finish();
207     }
208   }
209 
210   @Override
onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults)211   public void onRequestPermissionsResult(
212       int requestCode, String[] permissions, int[] grantResults) {
213     if (requestCode == PERMISSION_REQUEST) {
214       String[] missingPermissions = getMissingPermissions();
215       if (missingPermissions.length != 0) {
216         // User didn't grant all the permissions. Warn that the application might not work
217         // correctly.
218         new AlertDialog.Builder(this)
219             .setMessage(R.string.missing_permissions_try_again)
220             .setPositiveButton(R.string.yes,
221                 (dialog, id) -> {
222                   // User wants to try giving the permissions again.
223                   dialog.cancel();
224                   requestPermissions();
225                 })
226             .setNegativeButton(R.string.no,
227                 (dialog, id) -> {
228                   // User doesn't want to give the permissions.
229                   dialog.cancel();
230                   onPermissionsGranted();
231                 })
232             .show();
233       } else {
234         // All permissions granted.
235         onPermissionsGranted();
236       }
237     }
238   }
239 
onPermissionsGranted()240   private void onPermissionsGranted() {
241     // If an implicit VIEW intent is launching the app, go directly to that URL.
242     final Intent intent = getIntent();
243     if ("android.intent.action.VIEW".equals(intent.getAction()) && !commandLineRun) {
244       boolean loopback = intent.getBooleanExtra(CallActivity.EXTRA_LOOPBACK, false);
245       int runTimeMs = intent.getIntExtra(CallActivity.EXTRA_RUNTIME, 0);
246       boolean useValuesFromIntent =
247           intent.getBooleanExtra(CallActivity.EXTRA_USE_VALUES_FROM_INTENT, false);
248       String room = sharedPref.getString(keyprefRoom, "");
249       connectToRoom(room, true, loopback, useValuesFromIntent, runTimeMs);
250     }
251   }
252 
253   @TargetApi(Build.VERSION_CODES.M)
requestPermissions()254   private void requestPermissions() {
255     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
256       // Dynamic permissions are not required before Android M.
257       onPermissionsGranted();
258       return;
259     }
260 
261     String[] missingPermissions = getMissingPermissions();
262     if (missingPermissions.length != 0) {
263       requestPermissions(missingPermissions, PERMISSION_REQUEST);
264     } else {
265       onPermissionsGranted();
266     }
267   }
268 
269   @TargetApi(Build.VERSION_CODES.M)
getMissingPermissions()270   private String[] getMissingPermissions() {
271     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
272       return new String[0];
273     }
274 
275     PackageInfo info;
276     try {
277       info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS);
278     } catch (PackageManager.NameNotFoundException e) {
279       Log.w(TAG, "Failed to retrieve permissions.");
280       return new String[0];
281     }
282 
283     if (info.requestedPermissions == null) {
284       Log.w(TAG, "No requested permissions.");
285       return new String[0];
286     }
287 
288     ArrayList<String> missingPermissions = new ArrayList<>();
289     for (int i = 0; i < info.requestedPermissions.length; i++) {
290       if ((info.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
291         missingPermissions.add(info.requestedPermissions[i]);
292       }
293     }
294     Log.d(TAG, "Missing permissions: " + missingPermissions);
295 
296     return missingPermissions.toArray(new String[missingPermissions.size()]);
297   }
298 
299   /**
300    * Get a value from the shared preference or from the intent, if it does not
301    * exist the default is used.
302    */
303   @Nullable
sharedPrefGetString( int attributeId, String intentName, int defaultId, boolean useFromIntent)304   private String sharedPrefGetString(
305       int attributeId, String intentName, int defaultId, boolean useFromIntent) {
306     String defaultValue = getString(defaultId);
307     if (useFromIntent) {
308       String value = getIntent().getStringExtra(intentName);
309       if (value != null) {
310         return value;
311       }
312       return defaultValue;
313     } else {
314       String attributeName = getString(attributeId);
315       return sharedPref.getString(attributeName, defaultValue);
316     }
317   }
318 
319   /**
320    * Get a value from the shared preference or from the intent, if it does not
321    * exist the default is used.
322    */
sharedPrefGetBoolean( int attributeId, String intentName, int defaultId, boolean useFromIntent)323   private boolean sharedPrefGetBoolean(
324       int attributeId, String intentName, int defaultId, boolean useFromIntent) {
325     boolean defaultValue = Boolean.parseBoolean(getString(defaultId));
326     if (useFromIntent) {
327       return getIntent().getBooleanExtra(intentName, defaultValue);
328     } else {
329       String attributeName = getString(attributeId);
330       return sharedPref.getBoolean(attributeName, defaultValue);
331     }
332   }
333 
334   /**
335    * Get a value from the shared preference or from the intent, if it does not
336    * exist the default is used.
337    */
sharedPrefGetInteger( int attributeId, String intentName, int defaultId, boolean useFromIntent)338   private int sharedPrefGetInteger(
339       int attributeId, String intentName, int defaultId, boolean useFromIntent) {
340     String defaultString = getString(defaultId);
341     int defaultValue = Integer.parseInt(defaultString);
342     if (useFromIntent) {
343       return getIntent().getIntExtra(intentName, defaultValue);
344     } else {
345       String attributeName = getString(attributeId);
346       String value = sharedPref.getString(attributeName, defaultString);
347       try {
348         return Integer.parseInt(value);
349       } catch (NumberFormatException e) {
350         Log.e(TAG, "Wrong setting for: " + attributeName + ":" + value);
351         return defaultValue;
352       }
353     }
354   }
355 
356   @SuppressWarnings("StringSplitter")
connectToRoom(String roomId, boolean commandLineRun, boolean loopback, boolean useValuesFromIntent, int runTimeMs)357   private void connectToRoom(String roomId, boolean commandLineRun, boolean loopback,
358       boolean useValuesFromIntent, int runTimeMs) {
359     ConnectActivity.commandLineRun = commandLineRun;
360 
361     // roomId is random for loopback.
362     if (loopback) {
363       roomId = Integer.toString((new Random()).nextInt(100000000));
364     }
365 
366     String roomUrl = sharedPref.getString(
367         keyprefRoomServerUrl, getString(R.string.pref_room_server_url_default));
368 
369     // Video call enabled flag.
370     boolean videoCallEnabled = sharedPrefGetBoolean(R.string.pref_videocall_key,
371         CallActivity.EXTRA_VIDEO_CALL, R.string.pref_videocall_default, useValuesFromIntent);
372 
373     // Use screencapture option.
374     boolean useScreencapture = sharedPrefGetBoolean(R.string.pref_screencapture_key,
375         CallActivity.EXTRA_SCREENCAPTURE, R.string.pref_screencapture_default, useValuesFromIntent);
376 
377     // Use Camera2 option.
378     boolean useCamera2 = sharedPrefGetBoolean(R.string.pref_camera2_key, CallActivity.EXTRA_CAMERA2,
379         R.string.pref_camera2_default, useValuesFromIntent);
380 
381     // Get default codecs.
382     String videoCodec = sharedPrefGetString(R.string.pref_videocodec_key,
383         CallActivity.EXTRA_VIDEOCODEC, R.string.pref_videocodec_default, useValuesFromIntent);
384     String audioCodec = sharedPrefGetString(R.string.pref_audiocodec_key,
385         CallActivity.EXTRA_AUDIOCODEC, R.string.pref_audiocodec_default, useValuesFromIntent);
386 
387     // Check HW codec flag.
388     boolean hwCodec = sharedPrefGetBoolean(R.string.pref_hwcodec_key,
389         CallActivity.EXTRA_HWCODEC_ENABLED, R.string.pref_hwcodec_default, useValuesFromIntent);
390 
391     // Check Capture to texture.
392     boolean captureToTexture = sharedPrefGetBoolean(R.string.pref_capturetotexture_key,
393         CallActivity.EXTRA_CAPTURETOTEXTURE_ENABLED, R.string.pref_capturetotexture_default,
394         useValuesFromIntent);
395 
396     // Check FlexFEC.
397     boolean flexfecEnabled = sharedPrefGetBoolean(R.string.pref_flexfec_key,
398         CallActivity.EXTRA_FLEXFEC_ENABLED, R.string.pref_flexfec_default, useValuesFromIntent);
399 
400     // Check Disable Audio Processing flag.
401     boolean noAudioProcessing = sharedPrefGetBoolean(R.string.pref_noaudioprocessing_key,
402         CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, R.string.pref_noaudioprocessing_default,
403         useValuesFromIntent);
404 
405     boolean aecDump = sharedPrefGetBoolean(R.string.pref_aecdump_key,
406         CallActivity.EXTRA_AECDUMP_ENABLED, R.string.pref_aecdump_default, useValuesFromIntent);
407 
408     boolean saveInputAudioToFile =
409         sharedPrefGetBoolean(R.string.pref_enable_save_input_audio_to_file_key,
410             CallActivity.EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED,
411             R.string.pref_enable_save_input_audio_to_file_default, useValuesFromIntent);
412 
413     // Check OpenSL ES enabled flag.
414     boolean useOpenSLES = sharedPrefGetBoolean(R.string.pref_opensles_key,
415         CallActivity.EXTRA_OPENSLES_ENABLED, R.string.pref_opensles_default, useValuesFromIntent);
416 
417     // Check Disable built-in AEC flag.
418     boolean disableBuiltInAEC = sharedPrefGetBoolean(R.string.pref_disable_built_in_aec_key,
419         CallActivity.EXTRA_DISABLE_BUILT_IN_AEC, R.string.pref_disable_built_in_aec_default,
420         useValuesFromIntent);
421 
422     // Check Disable built-in AGC flag.
423     boolean disableBuiltInAGC = sharedPrefGetBoolean(R.string.pref_disable_built_in_agc_key,
424         CallActivity.EXTRA_DISABLE_BUILT_IN_AGC, R.string.pref_disable_built_in_agc_default,
425         useValuesFromIntent);
426 
427     // Check Disable built-in NS flag.
428     boolean disableBuiltInNS = sharedPrefGetBoolean(R.string.pref_disable_built_in_ns_key,
429         CallActivity.EXTRA_DISABLE_BUILT_IN_NS, R.string.pref_disable_built_in_ns_default,
430         useValuesFromIntent);
431 
432     // Check Disable gain control
433     boolean disableWebRtcAGCAndHPF = sharedPrefGetBoolean(
434         R.string.pref_disable_webrtc_agc_and_hpf_key, CallActivity.EXTRA_DISABLE_WEBRTC_AGC_AND_HPF,
435         R.string.pref_disable_webrtc_agc_and_hpf_key, useValuesFromIntent);
436 
437     // Get video resolution from settings.
438     int videoWidth = 0;
439     int videoHeight = 0;
440     if (useValuesFromIntent) {
441       videoWidth = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_WIDTH, 0);
442       videoHeight = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_HEIGHT, 0);
443     }
444     if (videoWidth == 0 && videoHeight == 0) {
445       String resolution =
446           sharedPref.getString(keyprefResolution, getString(R.string.pref_resolution_default));
447       String[] dimensions = resolution.split("[ x]+");
448       if (dimensions.length == 2) {
449         try {
450           videoWidth = Integer.parseInt(dimensions[0]);
451           videoHeight = Integer.parseInt(dimensions[1]);
452         } catch (NumberFormatException e) {
453           videoWidth = 0;
454           videoHeight = 0;
455           Log.e(TAG, "Wrong video resolution setting: " + resolution);
456         }
457       }
458     }
459 
460     // Get camera fps from settings.
461     int cameraFps = 0;
462     if (useValuesFromIntent) {
463       cameraFps = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_FPS, 0);
464     }
465     if (cameraFps == 0) {
466       String fps = sharedPref.getString(keyprefFps, getString(R.string.pref_fps_default));
467       String[] fpsValues = fps.split("[ x]+");
468       if (fpsValues.length == 2) {
469         try {
470           cameraFps = Integer.parseInt(fpsValues[0]);
471         } catch (NumberFormatException e) {
472           cameraFps = 0;
473           Log.e(TAG, "Wrong camera fps setting: " + fps);
474         }
475       }
476     }
477 
478     // Check capture quality slider flag.
479     boolean captureQualitySlider = sharedPrefGetBoolean(R.string.pref_capturequalityslider_key,
480         CallActivity.EXTRA_VIDEO_CAPTUREQUALITYSLIDER_ENABLED,
481         R.string.pref_capturequalityslider_default, useValuesFromIntent);
482 
483     // Get video and audio start bitrate.
484     int videoStartBitrate = 0;
485     if (useValuesFromIntent) {
486       videoStartBitrate = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_BITRATE, 0);
487     }
488     if (videoStartBitrate == 0) {
489       String bitrateTypeDefault = getString(R.string.pref_maxvideobitrate_default);
490       String bitrateType = sharedPref.getString(keyprefVideoBitrateType, bitrateTypeDefault);
491       if (!bitrateType.equals(bitrateTypeDefault)) {
492         String bitrateValue = sharedPref.getString(
493             keyprefVideoBitrateValue, getString(R.string.pref_maxvideobitratevalue_default));
494         videoStartBitrate = Integer.parseInt(bitrateValue);
495       }
496     }
497 
498     int audioStartBitrate = 0;
499     if (useValuesFromIntent) {
500       audioStartBitrate = getIntent().getIntExtra(CallActivity.EXTRA_AUDIO_BITRATE, 0);
501     }
502     if (audioStartBitrate == 0) {
503       String bitrateTypeDefault = getString(R.string.pref_startaudiobitrate_default);
504       String bitrateType = sharedPref.getString(keyprefAudioBitrateType, bitrateTypeDefault);
505       if (!bitrateType.equals(bitrateTypeDefault)) {
506         String bitrateValue = sharedPref.getString(
507             keyprefAudioBitrateValue, getString(R.string.pref_startaudiobitratevalue_default));
508         audioStartBitrate = Integer.parseInt(bitrateValue);
509       }
510     }
511 
512     // Check statistics display option.
513     boolean displayHud = sharedPrefGetBoolean(R.string.pref_displayhud_key,
514         CallActivity.EXTRA_DISPLAY_HUD, R.string.pref_displayhud_default, useValuesFromIntent);
515 
516     boolean tracing = sharedPrefGetBoolean(R.string.pref_tracing_key, CallActivity.EXTRA_TRACING,
517         R.string.pref_tracing_default, useValuesFromIntent);
518 
519     // Check Enable RtcEventLog.
520     boolean rtcEventLogEnabled = sharedPrefGetBoolean(R.string.pref_enable_rtceventlog_key,
521         CallActivity.EXTRA_ENABLE_RTCEVENTLOG, R.string.pref_enable_rtceventlog_default,
522         useValuesFromIntent);
523 
524     // Get datachannel options
525     boolean dataChannelEnabled = sharedPrefGetBoolean(R.string.pref_enable_datachannel_key,
526         CallActivity.EXTRA_DATA_CHANNEL_ENABLED, R.string.pref_enable_datachannel_default,
527         useValuesFromIntent);
528     boolean ordered = sharedPrefGetBoolean(R.string.pref_ordered_key, CallActivity.EXTRA_ORDERED,
529         R.string.pref_ordered_default, useValuesFromIntent);
530     boolean negotiated = sharedPrefGetBoolean(R.string.pref_negotiated_key,
531         CallActivity.EXTRA_NEGOTIATED, R.string.pref_negotiated_default, useValuesFromIntent);
532     int maxRetrMs = sharedPrefGetInteger(R.string.pref_max_retransmit_time_ms_key,
533         CallActivity.EXTRA_MAX_RETRANSMITS_MS, R.string.pref_max_retransmit_time_ms_default,
534         useValuesFromIntent);
535     int maxRetr =
536         sharedPrefGetInteger(R.string.pref_max_retransmits_key, CallActivity.EXTRA_MAX_RETRANSMITS,
537             R.string.pref_max_retransmits_default, useValuesFromIntent);
538     int id = sharedPrefGetInteger(R.string.pref_data_id_key, CallActivity.EXTRA_ID,
539         R.string.pref_data_id_default, useValuesFromIntent);
540     String protocol = sharedPrefGetString(R.string.pref_data_protocol_key,
541         CallActivity.EXTRA_PROTOCOL, R.string.pref_data_protocol_default, useValuesFromIntent);
542 
543     // Start AppRTCMobile activity.
544     Log.d(TAG, "Connecting to room " + roomId + " at URL " + roomUrl);
545     if (validateUrl(roomUrl)) {
546       Uri uri = Uri.parse(roomUrl);
547       Intent intent = new Intent(this, CallActivity.class);
548       intent.setData(uri);
549       intent.putExtra(CallActivity.EXTRA_ROOMID, roomId);
550       intent.putExtra(CallActivity.EXTRA_LOOPBACK, loopback);
551       intent.putExtra(CallActivity.EXTRA_VIDEO_CALL, videoCallEnabled);
552       intent.putExtra(CallActivity.EXTRA_SCREENCAPTURE, useScreencapture);
553       intent.putExtra(CallActivity.EXTRA_CAMERA2, useCamera2);
554       intent.putExtra(CallActivity.EXTRA_VIDEO_WIDTH, videoWidth);
555       intent.putExtra(CallActivity.EXTRA_VIDEO_HEIGHT, videoHeight);
556       intent.putExtra(CallActivity.EXTRA_VIDEO_FPS, cameraFps);
557       intent.putExtra(CallActivity.EXTRA_VIDEO_CAPTUREQUALITYSLIDER_ENABLED, captureQualitySlider);
558       intent.putExtra(CallActivity.EXTRA_VIDEO_BITRATE, videoStartBitrate);
559       intent.putExtra(CallActivity.EXTRA_VIDEOCODEC, videoCodec);
560       intent.putExtra(CallActivity.EXTRA_HWCODEC_ENABLED, hwCodec);
561       intent.putExtra(CallActivity.EXTRA_CAPTURETOTEXTURE_ENABLED, captureToTexture);
562       intent.putExtra(CallActivity.EXTRA_FLEXFEC_ENABLED, flexfecEnabled);
563       intent.putExtra(CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, noAudioProcessing);
564       intent.putExtra(CallActivity.EXTRA_AECDUMP_ENABLED, aecDump);
565       intent.putExtra(CallActivity.EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED, saveInputAudioToFile);
566       intent.putExtra(CallActivity.EXTRA_OPENSLES_ENABLED, useOpenSLES);
567       intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_AEC, disableBuiltInAEC);
568       intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_AGC, disableBuiltInAGC);
569       intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_NS, disableBuiltInNS);
570       intent.putExtra(CallActivity.EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, disableWebRtcAGCAndHPF);
571       intent.putExtra(CallActivity.EXTRA_AUDIO_BITRATE, audioStartBitrate);
572       intent.putExtra(CallActivity.EXTRA_AUDIOCODEC, audioCodec);
573       intent.putExtra(CallActivity.EXTRA_DISPLAY_HUD, displayHud);
574       intent.putExtra(CallActivity.EXTRA_TRACING, tracing);
575       intent.putExtra(CallActivity.EXTRA_ENABLE_RTCEVENTLOG, rtcEventLogEnabled);
576       intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun);
577       intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs);
578       intent.putExtra(CallActivity.EXTRA_DATA_CHANNEL_ENABLED, dataChannelEnabled);
579 
580       if (dataChannelEnabled) {
581         intent.putExtra(CallActivity.EXTRA_ORDERED, ordered);
582         intent.putExtra(CallActivity.EXTRA_MAX_RETRANSMITS_MS, maxRetrMs);
583         intent.putExtra(CallActivity.EXTRA_MAX_RETRANSMITS, maxRetr);
584         intent.putExtra(CallActivity.EXTRA_PROTOCOL, protocol);
585         intent.putExtra(CallActivity.EXTRA_NEGOTIATED, negotiated);
586         intent.putExtra(CallActivity.EXTRA_ID, id);
587       }
588 
589       if (useValuesFromIntent) {
590         if (getIntent().hasExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA)) {
591           String videoFileAsCamera =
592               getIntent().getStringExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA);
593           intent.putExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA, videoFileAsCamera);
594         }
595 
596         if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE)) {
597           String saveRemoteVideoToFile =
598               getIntent().getStringExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE);
599           intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE, saveRemoteVideoToFile);
600         }
601 
602         if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH)) {
603           int videoOutWidth =
604               getIntent().getIntExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, 0);
605           intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, videoOutWidth);
606         }
607 
608         if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT)) {
609           int videoOutHeight =
610               getIntent().getIntExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, 0);
611           intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, videoOutHeight);
612         }
613       }
614 
615       startActivityForResult(intent, CONNECTION_REQUEST);
616     }
617   }
618 
validateUrl(String url)619   private boolean validateUrl(String url) {
620     if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) {
621       return true;
622     }
623 
624     new AlertDialog.Builder(this)
625         .setTitle(getText(R.string.invalid_url_title))
626         .setMessage(getString(R.string.invalid_url_text, url))
627         .setCancelable(false)
628         .setNeutralButton(R.string.ok,
629             new DialogInterface.OnClickListener() {
630               @Override
631               public void onClick(DialogInterface dialog, int id) {
632                 dialog.cancel();
633               }
634             })
635         .create()
636         .show();
637     return false;
638   }
639 
640   private final AdapterView.OnItemClickListener roomListClickListener =
641       new AdapterView.OnItemClickListener() {
642         @Override
643         public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
644           String roomId = ((TextView) view).getText().toString();
645           connectToRoom(roomId, false, false, false, 0);
646         }
647       };
648 
649   private final OnClickListener addFavoriteListener = new OnClickListener() {
650     @Override
651     public void onClick(View view) {
652       String newRoom = roomEditText.getText().toString();
653       if (newRoom.length() > 0 && !roomList.contains(newRoom)) {
654         adapter.add(newRoom);
655         adapter.notifyDataSetChanged();
656       }
657     }
658   };
659 
660   private final OnClickListener connectListener = new OnClickListener() {
661     @Override
662     public void onClick(View view) {
663       connectToRoom(roomEditText.getText().toString(), false, false, false, 0);
664     }
665   };
666 }
667