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 |