| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * libjingle | |
| 3 * Copyright 2014 Google Inc. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright notice, | |
| 9 * this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| 11 * this list of conditions and the following disclaimer in the documentation | |
| 12 * and/or other materials provided with the distribution. | |
| 13 * 3. The name of the author may not be used to endorse or promote products | |
| 14 * derived from this software without specific prior written permission. | |
| 15 * | |
| 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
| 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
| 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
| 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
| 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
| 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 26 */ | |
| 27 | |
| 28 package org.appspot.apprtc; | |
| 29 | |
| 30 import android.app.Activity; | |
| 31 import android.app.AlertDialog; | |
| 32 import android.content.DialogInterface; | |
| 33 import android.content.Intent; | |
| 34 import android.content.SharedPreferences; | |
| 35 import android.net.Uri; | |
| 36 import android.os.Bundle; | |
| 37 import android.preference.PreferenceManager; | |
| 38 import android.util.Log; | |
| 39 import android.view.KeyEvent; | |
| 40 import android.view.Menu; | |
| 41 import android.view.MenuItem; | |
| 42 import android.view.View; | |
| 43 import android.view.View.OnClickListener; | |
| 44 import android.view.inputmethod.EditorInfo; | |
| 45 import android.webkit.URLUtil; | |
| 46 import android.widget.AdapterView; | |
| 47 import android.widget.ArrayAdapter; | |
| 48 import android.widget.EditText; | |
| 49 import android.widget.ImageButton; | |
| 50 import android.widget.ListView; | |
| 51 import android.widget.TextView; | |
| 52 | |
| 53 import org.json.JSONArray; | |
| 54 import org.json.JSONException; | |
| 55 | |
| 56 import java.util.ArrayList; | |
| 57 import java.util.Random; | |
| 58 | |
| 59 /** | |
| 60 * Handles the initial setup where the user selects which room to join. | |
| 61 */ | |
| 62 public class ConnectActivity extends Activity { | |
| 63 private static final String TAG = "ConnectActivity"; | |
| 64 private static final int CONNECTION_REQUEST = 1; | |
| 65 private static boolean commandLineRun = false; | |
| 66 | |
| 67 private ImageButton addRoomButton; | |
| 68 private ImageButton removeRoomButton; | |
| 69 private ImageButton connectButton; | |
| 70 private ImageButton connectLoopbackButton; | |
| 71 private EditText roomEditText; | |
| 72 private ListView roomListView; | |
| 73 private SharedPreferences sharedPref; | |
| 74 private String keyprefVideoCallEnabled; | |
| 75 private String keyprefResolution; | |
| 76 private String keyprefFps; | |
| 77 private String keyprefVideoBitrateType; | |
| 78 private String keyprefVideoBitrateValue; | |
| 79 private String keyprefVideoCodec; | |
| 80 private String keyprefAudioBitrateType; | |
| 81 private String keyprefAudioBitrateValue; | |
| 82 private String keyprefAudioCodec; | |
| 83 private String keyprefHwCodecAcceleration; | |
| 84 private String keyprefNoAudioProcessingPipeline; | |
| 85 private String keyprefCpuUsageDetection; | |
| 86 private String keyprefDisplayHud; | |
| 87 private String keyprefRoomServerUrl; | |
| 88 private String keyprefRoom; | |
| 89 private String keyprefRoomList; | |
| 90 private ArrayList<String> roomList; | |
| 91 private ArrayAdapter<String> adapter; | |
| 92 | |
| 93 @Override | |
| 94 public void onCreate(Bundle savedInstanceState) { | |
| 95 super.onCreate(savedInstanceState); | |
| 96 | |
| 97 // Get setting keys. | |
| 98 PreferenceManager.setDefaultValues(this, R.xml.preferences, false); | |
| 99 sharedPref = PreferenceManager.getDefaultSharedPreferences(this); | |
| 100 keyprefVideoCallEnabled = getString(R.string.pref_videocall_key); | |
| 101 keyprefResolution = getString(R.string.pref_resolution_key); | |
| 102 keyprefFps = getString(R.string.pref_fps_key); | |
| 103 keyprefVideoBitrateType = getString(R.string.pref_startvideobitrate_key); | |
| 104 keyprefVideoBitrateValue = getString(R.string.pref_startvideobitratevalue_ke
y); | |
| 105 keyprefVideoCodec = getString(R.string.pref_videocodec_key); | |
| 106 keyprefHwCodecAcceleration = getString(R.string.pref_hwcodec_key); | |
| 107 keyprefAudioBitrateType = getString(R.string.pref_startaudiobitrate_key); | |
| 108 keyprefAudioBitrateValue = getString(R.string.pref_startaudiobitratevalue_ke
y); | |
| 109 keyprefAudioCodec = getString(R.string.pref_audiocodec_key); | |
| 110 keyprefNoAudioProcessingPipeline = getString(R.string.pref_noaudioprocessing
_key); | |
| 111 keyprefCpuUsageDetection = getString(R.string.pref_cpu_usage_detection_key); | |
| 112 keyprefDisplayHud = getString(R.string.pref_displayhud_key); | |
| 113 keyprefRoomServerUrl = getString(R.string.pref_room_server_url_key); | |
| 114 keyprefRoom = getString(R.string.pref_room_key); | |
| 115 keyprefRoomList = getString(R.string.pref_room_list_key); | |
| 116 | |
| 117 setContentView(R.layout.activity_connect); | |
| 118 | |
| 119 roomEditText = (EditText) findViewById(R.id.room_edittext); | |
| 120 roomEditText.setOnEditorActionListener( | |
| 121 new TextView.OnEditorActionListener() { | |
| 122 @Override | |
| 123 public boolean onEditorAction( | |
| 124 TextView textView, int i, KeyEvent keyEvent) { | |
| 125 if (i == EditorInfo.IME_ACTION_DONE) { | |
| 126 addRoomButton.performClick(); | |
| 127 return true; | |
| 128 } | |
| 129 return false; | |
| 130 } | |
| 131 }); | |
| 132 roomEditText.requestFocus(); | |
| 133 | |
| 134 roomListView = (ListView) findViewById(R.id.room_listview); | |
| 135 roomListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); | |
| 136 | |
| 137 addRoomButton = (ImageButton) findViewById(R.id.add_room_button); | |
| 138 addRoomButton.setOnClickListener(addRoomListener); | |
| 139 removeRoomButton = (ImageButton) findViewById(R.id.remove_room_button); | |
| 140 removeRoomButton.setOnClickListener(removeRoomListener); | |
| 141 connectButton = (ImageButton) findViewById(R.id.connect_button); | |
| 142 connectButton.setOnClickListener(connectListener); | |
| 143 connectLoopbackButton = | |
| 144 (ImageButton) findViewById(R.id.connect_loopback_button); | |
| 145 connectLoopbackButton.setOnClickListener(connectListener); | |
| 146 | |
| 147 // If an implicit VIEW intent is launching the app, go directly to that URL. | |
| 148 final Intent intent = getIntent(); | |
| 149 if ("android.intent.action.VIEW".equals(intent.getAction()) | |
| 150 && !commandLineRun) { | |
| 151 commandLineRun = true; | |
| 152 boolean loopback = intent.getBooleanExtra( | |
| 153 CallActivity.EXTRA_LOOPBACK, false); | |
| 154 int runTimeMs = intent.getIntExtra( | |
| 155 CallActivity.EXTRA_RUNTIME, 0); | |
| 156 String room = sharedPref.getString(keyprefRoom, ""); | |
| 157 roomEditText.setText(room); | |
| 158 connectToRoom(loopback, runTimeMs); | |
| 159 return; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 @Override | |
| 164 public boolean onCreateOptionsMenu(Menu menu) { | |
| 165 getMenuInflater().inflate(R.menu.connect_menu, menu); | |
| 166 return true; | |
| 167 } | |
| 168 | |
| 169 @Override | |
| 170 public boolean onOptionsItemSelected(MenuItem item) { | |
| 171 // Handle presses on the action bar items. | |
| 172 if (item.getItemId() == R.id.action_settings) { | |
| 173 Intent intent = new Intent(this, SettingsActivity.class); | |
| 174 startActivity(intent); | |
| 175 return true; | |
| 176 } else { | |
| 177 return super.onOptionsItemSelected(item); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 @Override | |
| 182 public void onPause() { | |
| 183 super.onPause(); | |
| 184 String room = roomEditText.getText().toString(); | |
| 185 String roomListJson = new JSONArray(roomList).toString(); | |
| 186 SharedPreferences.Editor editor = sharedPref.edit(); | |
| 187 editor.putString(keyprefRoom, room); | |
| 188 editor.putString(keyprefRoomList, roomListJson); | |
| 189 editor.commit(); | |
| 190 } | |
| 191 | |
| 192 @Override | |
| 193 public void onResume() { | |
| 194 super.onResume(); | |
| 195 String room = sharedPref.getString(keyprefRoom, ""); | |
| 196 roomEditText.setText(room); | |
| 197 roomList = new ArrayList<String>(); | |
| 198 String roomListJson = sharedPref.getString(keyprefRoomList, null); | |
| 199 if (roomListJson != null) { | |
| 200 try { | |
| 201 JSONArray jsonArray = new JSONArray(roomListJson); | |
| 202 for (int i = 0; i < jsonArray.length(); i++) { | |
| 203 roomList.add(jsonArray.get(i).toString()); | |
| 204 } | |
| 205 } catch (JSONException e) { | |
| 206 Log.e(TAG, "Failed to load room list: " + e.toString()); | |
| 207 } | |
| 208 } | |
| 209 adapter = new ArrayAdapter<String>( | |
| 210 this, android.R.layout.simple_list_item_1, roomList); | |
| 211 roomListView.setAdapter(adapter); | |
| 212 if (adapter.getCount() > 0) { | |
| 213 roomListView.requestFocus(); | |
| 214 roomListView.setItemChecked(0, true); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 @Override | |
| 219 protected void onActivityResult( | |
| 220 int requestCode, int resultCode, Intent data) { | |
| 221 if (requestCode == CONNECTION_REQUEST && commandLineRun) { | |
| 222 Log.d(TAG, "Return: " + resultCode); | |
| 223 setResult(resultCode); | |
| 224 commandLineRun = false; | |
| 225 finish(); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 private final OnClickListener connectListener = new OnClickListener() { | |
| 230 @Override | |
| 231 public void onClick(View view) { | |
| 232 boolean loopback = false; | |
| 233 if (view.getId() == R.id.connect_loopback_button) { | |
| 234 loopback = true; | |
| 235 } | |
| 236 commandLineRun = false; | |
| 237 connectToRoom(loopback, 0); | |
| 238 } | |
| 239 }; | |
| 240 | |
| 241 private void connectToRoom(boolean loopback, int runTimeMs) { | |
| 242 // Get room name (random for loopback). | |
| 243 String roomId; | |
| 244 if (loopback) { | |
| 245 roomId = Integer.toString((new Random()).nextInt(100000000)); | |
| 246 } else { | |
| 247 roomId = getSelectedItem(); | |
| 248 if (roomId == null) { | |
| 249 roomId = roomEditText.getText().toString(); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 String roomUrl = sharedPref.getString( | |
| 254 keyprefRoomServerUrl, | |
| 255 getString(R.string.pref_room_server_url_default)); | |
| 256 | |
| 257 // Video call enabled flag. | |
| 258 boolean videoCallEnabled = sharedPref.getBoolean(keyprefVideoCallEnabled, | |
| 259 Boolean.valueOf(getString(R.string.pref_videocall_default))); | |
| 260 | |
| 261 // Get default codecs. | |
| 262 String videoCodec = sharedPref.getString(keyprefVideoCodec, | |
| 263 getString(R.string.pref_videocodec_default)); | |
| 264 String audioCodec = sharedPref.getString(keyprefAudioCodec, | |
| 265 getString(R.string.pref_audiocodec_default)); | |
| 266 | |
| 267 // Check HW codec flag. | |
| 268 boolean hwCodec = sharedPref.getBoolean(keyprefHwCodecAcceleration, | |
| 269 Boolean.valueOf(getString(R.string.pref_hwcodec_default))); | |
| 270 | |
| 271 // Check Disable Audio Processing flag. | |
| 272 boolean noAudioProcessing = sharedPref.getBoolean( | |
| 273 keyprefNoAudioProcessingPipeline, | |
| 274 Boolean.valueOf(getString(R.string.pref_noaudioprocessing_default))); | |
| 275 | |
| 276 // Get video resolution from settings. | |
| 277 int videoWidth = 0; | |
| 278 int videoHeight = 0; | |
| 279 String resolution = sharedPref.getString(keyprefResolution, | |
| 280 getString(R.string.pref_resolution_default)); | |
| 281 String[] dimensions = resolution.split("[ x]+"); | |
| 282 if (dimensions.length == 2) { | |
| 283 try { | |
| 284 videoWidth = Integer.parseInt(dimensions[0]); | |
| 285 videoHeight = Integer.parseInt(dimensions[1]); | |
| 286 } catch (NumberFormatException e) { | |
| 287 videoWidth = 0; | |
| 288 videoHeight = 0; | |
| 289 Log.e(TAG, "Wrong video resolution setting: " + resolution); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 // Get camera fps from settings. | |
| 294 int cameraFps = 0; | |
| 295 String fps = sharedPref.getString(keyprefFps, | |
| 296 getString(R.string.pref_fps_default)); | |
| 297 String[] fpsValues = fps.split("[ x]+"); | |
| 298 if (fpsValues.length == 2) { | |
| 299 try { | |
| 300 cameraFps = Integer.parseInt(fpsValues[0]); | |
| 301 } catch (NumberFormatException e) { | |
| 302 Log.e(TAG, "Wrong camera fps setting: " + fps); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 // Get video and audio start bitrate. | |
| 307 int videoStartBitrate = 0; | |
| 308 String bitrateTypeDefault = getString( | |
| 309 R.string.pref_startvideobitrate_default); | |
| 310 String bitrateType = sharedPref.getString( | |
| 311 keyprefVideoBitrateType, bitrateTypeDefault); | |
| 312 if (!bitrateType.equals(bitrateTypeDefault)) { | |
| 313 String bitrateValue = sharedPref.getString(keyprefVideoBitrateValue, | |
| 314 getString(R.string.pref_startvideobitratevalue_default)); | |
| 315 videoStartBitrate = Integer.parseInt(bitrateValue); | |
| 316 } | |
| 317 int audioStartBitrate = 0; | |
| 318 bitrateTypeDefault = getString(R.string.pref_startaudiobitrate_default); | |
| 319 bitrateType = sharedPref.getString( | |
| 320 keyprefAudioBitrateType, bitrateTypeDefault); | |
| 321 if (!bitrateType.equals(bitrateTypeDefault)) { | |
| 322 String bitrateValue = sharedPref.getString(keyprefAudioBitrateValue, | |
| 323 getString(R.string.pref_startaudiobitratevalue_default)); | |
| 324 audioStartBitrate = Integer.parseInt(bitrateValue); | |
| 325 } | |
| 326 | |
| 327 // Test if CpuOveruseDetection should be disabled. By default is on. | |
| 328 boolean cpuOveruseDetection = sharedPref.getBoolean( | |
| 329 keyprefCpuUsageDetection, | |
| 330 Boolean.valueOf( | |
| 331 getString(R.string.pref_cpu_usage_detection_default))); | |
| 332 | |
| 333 // Check statistics display option. | |
| 334 boolean displayHud = sharedPref.getBoolean(keyprefDisplayHud, | |
| 335 Boolean.valueOf(getString(R.string.pref_displayhud_default))); | |
| 336 | |
| 337 // Start AppRTCDemo activity. | |
| 338 Log.d(TAG, "Connecting to room " + roomId + " at URL " + roomUrl); | |
| 339 if (validateUrl(roomUrl)) { | |
| 340 Uri uri = Uri.parse(roomUrl); | |
| 341 Intent intent = new Intent(this, CallActivity.class); | |
| 342 intent.setData(uri); | |
| 343 intent.putExtra(CallActivity.EXTRA_ROOMID, roomId); | |
| 344 intent.putExtra(CallActivity.EXTRA_LOOPBACK, loopback); | |
| 345 intent.putExtra(CallActivity.EXTRA_VIDEO_CALL, videoCallEnabled); | |
| 346 intent.putExtra(CallActivity.EXTRA_VIDEO_WIDTH, videoWidth); | |
| 347 intent.putExtra(CallActivity.EXTRA_VIDEO_HEIGHT, videoHeight); | |
| 348 intent.putExtra(CallActivity.EXTRA_VIDEO_FPS, cameraFps); | |
| 349 intent.putExtra(CallActivity.EXTRA_VIDEO_BITRATE, videoStartBitrate); | |
| 350 intent.putExtra(CallActivity.EXTRA_VIDEOCODEC, videoCodec); | |
| 351 intent.putExtra(CallActivity.EXTRA_HWCODEC_ENABLED, hwCodec); | |
| 352 intent.putExtra(CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, | |
| 353 noAudioProcessing); | |
| 354 intent.putExtra(CallActivity.EXTRA_AUDIO_BITRATE, audioStartBitrate); | |
| 355 intent.putExtra(CallActivity.EXTRA_AUDIOCODEC, audioCodec); | |
| 356 intent.putExtra(CallActivity.EXTRA_CPUOVERUSE_DETECTION, | |
| 357 cpuOveruseDetection); | |
| 358 intent.putExtra(CallActivity.EXTRA_DISPLAY_HUD, displayHud); | |
| 359 intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun); | |
| 360 intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs); | |
| 361 | |
| 362 startActivityForResult(intent, CONNECTION_REQUEST); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 private boolean validateUrl(String url) { | |
| 367 if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) { | |
| 368 return true; | |
| 369 } | |
| 370 | |
| 371 new AlertDialog.Builder(this) | |
| 372 .setTitle(getText(R.string.invalid_url_title)) | |
| 373 .setMessage(getString(R.string.invalid_url_text, url)) | |
| 374 .setCancelable(false) | |
| 375 .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { | |
| 376 public void onClick(DialogInterface dialog, int id) { | |
| 377 dialog.cancel(); | |
| 378 } | |
| 379 }).create().show(); | |
| 380 return false; | |
| 381 } | |
| 382 | |
| 383 private final OnClickListener addRoomListener = new OnClickListener() { | |
| 384 @Override | |
| 385 public void onClick(View view) { | |
| 386 String newRoom = roomEditText.getText().toString(); | |
| 387 if (newRoom.length() > 0 && !roomList.contains(newRoom)) { | |
| 388 adapter.add(newRoom); | |
| 389 adapter.notifyDataSetChanged(); | |
| 390 } | |
| 391 } | |
| 392 }; | |
| 393 | |
| 394 private final OnClickListener removeRoomListener = new OnClickListener() { | |
| 395 @Override | |
| 396 public void onClick(View view) { | |
| 397 String selectedRoom = getSelectedItem(); | |
| 398 if (selectedRoom != null) { | |
| 399 adapter.remove(selectedRoom); | |
| 400 adapter.notifyDataSetChanged(); | |
| 401 } | |
| 402 } | |
| 403 }; | |
| 404 | |
| 405 private String getSelectedItem() { | |
| 406 int position = AdapterView.INVALID_POSITION; | |
| 407 if (roomListView.getCheckedItemCount() > 0 && adapter.getCount() > 0) { | |
| 408 position = roomListView.getCheckedItemPosition(); | |
| 409 if (position >= adapter.getCount()) { | |
| 410 position = AdapterView.INVALID_POSITION; | |
| 411 } | |
| 412 } | |
| 413 if (position != AdapterView.INVALID_POSITION) { | |
| 414 return adapter.getItem(position); | |
| 415 } else { | |
| 416 return null; | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 } | |
| OLD | NEW |