tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ConnectActivity.java (27439B)


      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.util.Log;
     26 import android.view.ContextMenu;
     27 import android.view.KeyEvent;
     28 import android.view.Menu;
     29 import android.view.MenuItem;
     30 import android.view.View;
     31 import android.view.View.OnClickListener;
     32 import android.view.inputmethod.EditorInfo;
     33 import android.webkit.URLUtil;
     34 import android.widget.AdapterView;
     35 import android.widget.ArrayAdapter;
     36 import android.widget.EditText;
     37 import android.widget.ImageButton;
     38 import android.widget.ListView;
     39 import android.widget.TextView;
     40 import androidx.annotation.Nullable;
     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
     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
    117  public boolean onCreateOptionsMenu(Menu menu) {
    118    getMenuInflater().inflate(R.menu.connect_menu, menu);
    119    return true;
    120  }
    121 
    122  @Override
    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
    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
    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
    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
    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
    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
    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 
    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)
    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)
    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
    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   */
    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   */
    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")
    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 
    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 }