Home | History | Annotate | Download | only in apprtc
      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.app.Activity;
     14 import android.app.AlertDialog;
     15 import android.content.DialogInterface;
     16 import android.content.Intent;
     17 import android.content.SharedPreferences;
     18 import android.net.Uri;
     19 import android.os.Bundle;
     20 import android.preference.PreferenceManager;
     21 import android.util.Log;
     22 import android.view.KeyEvent;
     23 import android.view.Menu;
     24 import android.view.MenuItem;
     25 import android.view.View;
     26 import android.view.View.OnClickListener;
     27 import android.view.inputmethod.EditorInfo;
     28 import android.webkit.URLUtil;
     29 import android.widget.AdapterView;
     30 import android.widget.ArrayAdapter;
     31 import android.widget.EditText;
     32 import android.widget.ImageButton;
     33 import android.widget.ListView;
     34 import android.widget.TextView;
     35 
     36 import org.json.JSONArray;
     37 import org.json.JSONException;
     38 
     39 import java.util.ArrayList;
     40 import java.util.Random;
     41 
     42 /**
     43  * Handles the initial setup where the user selects which room to join.
     44  */
     45 public class ConnectActivity extends Activity {
     46   private static final String TAG = "ConnectActivity";
     47   private static final int CONNECTION_REQUEST = 1;
     48   private static boolean commandLineRun = false;
     49 
     50   private ImageButton addRoomButton;
     51   private ImageButton removeRoomButton;
     52   private ImageButton connectButton;
     53   private ImageButton connectLoopbackButton;
     54   private EditText roomEditText;
     55   private ListView roomListView;
     56   private SharedPreferences sharedPref;
     57   private String keyprefVideoCallEnabled;
     58   private String keyprefResolution;
     59   private String keyprefFps;
     60   private String keyprefCaptureQualitySlider;
     61   private String keyprefVideoBitrateType;
     62   private String keyprefVideoBitrateValue;
     63   private String keyprefVideoCodec;
     64   private String keyprefAudioBitrateType;
     65   private String keyprefAudioBitrateValue;
     66   private String keyprefAudioCodec;
     67   private String keyprefHwCodecAcceleration;
     68   private String keyprefCaptureToTexture;
     69   private String keyprefNoAudioProcessingPipeline;
     70   private String keyprefAecDump;
     71   private String keyprefOpenSLES;
     72   private String keyprefDisplayHud;
     73   private String keyprefTracing;
     74   private String keyprefRoomServerUrl;
     75   private String keyprefRoom;
     76   private String keyprefRoomList;
     77   private ArrayList<String> roomList;
     78   private ArrayAdapter<String> adapter;
     79 
     80   @Override
     81   public void onCreate(Bundle savedInstanceState) {
     82     super.onCreate(savedInstanceState);
     83 
     84     // Get setting keys.
     85     PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
     86     sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
     87     keyprefVideoCallEnabled = getString(R.string.pref_videocall_key);
     88     keyprefResolution = getString(R.string.pref_resolution_key);
     89     keyprefFps = getString(R.string.pref_fps_key);
     90     keyprefCaptureQualitySlider = getString(R.string.pref_capturequalityslider_key);
     91     keyprefVideoBitrateType = getString(R.string.pref_startvideobitrate_key);
     92     keyprefVideoBitrateValue = getString(R.string.pref_startvideobitratevalue_key);
     93     keyprefVideoCodec = getString(R.string.pref_videocodec_key);
     94     keyprefHwCodecAcceleration = getString(R.string.pref_hwcodec_key);
     95     keyprefCaptureToTexture = getString(R.string.pref_capturetotexture_key);
     96     keyprefAudioBitrateType = getString(R.string.pref_startaudiobitrate_key);
     97     keyprefAudioBitrateValue = getString(R.string.pref_startaudiobitratevalue_key);
     98     keyprefAudioCodec = getString(R.string.pref_audiocodec_key);
     99     keyprefNoAudioProcessingPipeline = getString(R.string.pref_noaudioprocessing_key);
    100     keyprefAecDump = getString(R.string.pref_aecdump_key);
    101     keyprefOpenSLES = getString(R.string.pref_opensles_key);
    102     keyprefDisplayHud = getString(R.string.pref_displayhud_key);
    103     keyprefTracing = getString(R.string.pref_tracing_key);
    104     keyprefRoomServerUrl = getString(R.string.pref_room_server_url_key);
    105     keyprefRoom = getString(R.string.pref_room_key);
    106     keyprefRoomList = getString(R.string.pref_room_list_key);
    107 
    108     setContentView(R.layout.activity_connect);
    109 
    110     roomEditText = (EditText) findViewById(R.id.room_edittext);
    111     roomEditText.setOnEditorActionListener(
    112       new TextView.OnEditorActionListener() {
    113         @Override
    114         public boolean onEditorAction(
    115             TextView textView, int i, KeyEvent keyEvent) {
    116           if (i == EditorInfo.IME_ACTION_DONE) {
    117             addRoomButton.performClick();
    118             return true;
    119           }
    120           return false;
    121         }
    122     });
    123     roomEditText.requestFocus();
    124 
    125     roomListView = (ListView) findViewById(R.id.room_listview);
    126     roomListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    127 
    128     addRoomButton = (ImageButton) findViewById(R.id.add_room_button);
    129     addRoomButton.setOnClickListener(addRoomListener);
    130     removeRoomButton = (ImageButton) findViewById(R.id.remove_room_button);
    131     removeRoomButton.setOnClickListener(removeRoomListener);
    132     connectButton = (ImageButton) findViewById(R.id.connect_button);
    133     connectButton.setOnClickListener(connectListener);
    134     connectLoopbackButton =
    135         (ImageButton) findViewById(R.id.connect_loopback_button);
    136     connectLoopbackButton.setOnClickListener(connectListener);
    137 
    138     // If an implicit VIEW intent is launching the app, go directly to that URL.
    139     final Intent intent = getIntent();
    140     if ("android.intent.action.VIEW".equals(intent.getAction())
    141         && !commandLineRun) {
    142       commandLineRun = true;
    143       boolean loopback = intent.getBooleanExtra(
    144           CallActivity.EXTRA_LOOPBACK, false);
    145       int runTimeMs = intent.getIntExtra(
    146           CallActivity.EXTRA_RUNTIME, 0);
    147       String room = sharedPref.getString(keyprefRoom, "");
    148       roomEditText.setText(room);
    149       connectToRoom(loopback, runTimeMs);
    150       return;
    151     }
    152   }
    153 
    154   @Override
    155   public boolean onCreateOptionsMenu(Menu menu) {
    156     getMenuInflater().inflate(R.menu.connect_menu, menu);
    157     return true;
    158   }
    159 
    160   @Override
    161   public boolean onOptionsItemSelected(MenuItem item) {
    162     // Handle presses on the action bar items.
    163     if (item.getItemId() == R.id.action_settings) {
    164       Intent intent = new Intent(this, SettingsActivity.class);
    165       startActivity(intent);
    166       return true;
    167     } else {
    168       return super.onOptionsItemSelected(item);
    169     }
    170   }
    171 
    172   @Override
    173   public void onPause() {
    174     super.onPause();
    175     String room = roomEditText.getText().toString();
    176     String roomListJson = new JSONArray(roomList).toString();
    177     SharedPreferences.Editor editor = sharedPref.edit();
    178     editor.putString(keyprefRoom, room);
    179     editor.putString(keyprefRoomList, roomListJson);
    180     editor.commit();
    181   }
    182 
    183   @Override
    184   public void onResume() {
    185     super.onResume();
    186     String room = sharedPref.getString(keyprefRoom, "");
    187     roomEditText.setText(room);
    188     roomList = new ArrayList<String>();
    189     String roomListJson = sharedPref.getString(keyprefRoomList, null);
    190     if (roomListJson != null) {
    191       try {
    192         JSONArray jsonArray = new JSONArray(roomListJson);
    193         for (int i = 0; i < jsonArray.length(); i++) {
    194           roomList.add(jsonArray.get(i).toString());
    195         }
    196       } catch (JSONException e) {
    197         Log.e(TAG, "Failed to load room list: " + e.toString());
    198       }
    199     }
    200     adapter = new ArrayAdapter<String>(
    201         this, android.R.layout.simple_list_item_1, roomList);
    202     roomListView.setAdapter(adapter);
    203     if (adapter.getCount() > 0) {
    204       roomListView.requestFocus();
    205       roomListView.setItemChecked(0, true);
    206     }
    207   }
    208 
    209   @Override
    210   protected void onActivityResult(
    211       int requestCode, int resultCode, Intent data) {
    212     if (requestCode == CONNECTION_REQUEST && commandLineRun) {
    213       Log.d(TAG, "Return: " + resultCode);
    214       setResult(resultCode);
    215       commandLineRun = false;
    216       finish();
    217     }
    218   }
    219 
    220   private final OnClickListener connectListener = new OnClickListener() {
    221     @Override
    222     public void onClick(View view) {
    223       boolean loopback = false;
    224       if (view.getId() == R.id.connect_loopback_button) {
    225         loopback = true;
    226       }
    227       commandLineRun = false;
    228       connectToRoom(loopback, 0);
    229     }
    230   };
    231 
    232   private void connectToRoom(boolean loopback, int runTimeMs) {
    233     // Get room name (random for loopback).
    234     String roomId;
    235     if (loopback) {
    236       roomId = Integer.toString((new Random()).nextInt(100000000));
    237     } else {
    238       roomId = getSelectedItem();
    239       if (roomId == null) {
    240         roomId = roomEditText.getText().toString();
    241       }
    242     }
    243 
    244     String roomUrl = sharedPref.getString(
    245         keyprefRoomServerUrl,
    246         getString(R.string.pref_room_server_url_default));
    247 
    248     // Video call enabled flag.
    249     boolean videoCallEnabled = sharedPref.getBoolean(keyprefVideoCallEnabled,
    250         Boolean.valueOf(getString(R.string.pref_videocall_default)));
    251 
    252     // Get default codecs.
    253     String videoCodec = sharedPref.getString(keyprefVideoCodec,
    254         getString(R.string.pref_videocodec_default));
    255     String audioCodec = sharedPref.getString(keyprefAudioCodec,
    256         getString(R.string.pref_audiocodec_default));
    257 
    258     // Check HW codec flag.
    259     boolean hwCodec = sharedPref.getBoolean(keyprefHwCodecAcceleration,
    260         Boolean.valueOf(getString(R.string.pref_hwcodec_default)));
    261 
    262     // Check Capture to texture.
    263     boolean captureToTexture = sharedPref.getBoolean(keyprefCaptureToTexture,
    264         Boolean.valueOf(getString(R.string.pref_capturetotexture_default)));
    265 
    266     // Check Disable Audio Processing flag.
    267     boolean noAudioProcessing = sharedPref.getBoolean(
    268         keyprefNoAudioProcessingPipeline,
    269         Boolean.valueOf(getString(R.string.pref_noaudioprocessing_default)));
    270 
    271     // Check Disable Audio Processing flag.
    272     boolean aecDump = sharedPref.getBoolean(
    273         keyprefAecDump,
    274         Boolean.valueOf(getString(R.string.pref_aecdump_default)));
    275 
    276     // Check OpenSL ES enabled flag.
    277     boolean useOpenSLES = sharedPref.getBoolean(
    278         keyprefOpenSLES,
    279         Boolean.valueOf(getString(R.string.pref_opensles_default)));
    280 
    281     // Get video resolution from settings.
    282     int videoWidth = 0;
    283     int videoHeight = 0;
    284     String resolution = sharedPref.getString(keyprefResolution,
    285         getString(R.string.pref_resolution_default));
    286     String[] dimensions = resolution.split("[ x]+");
    287     if (dimensions.length == 2) {
    288       try {
    289         videoWidth = Integer.parseInt(dimensions[0]);
    290         videoHeight = Integer.parseInt(dimensions[1]);
    291       } catch (NumberFormatException e) {
    292         videoWidth = 0;
    293         videoHeight = 0;
    294         Log.e(TAG, "Wrong video resolution setting: " + resolution);
    295       }
    296     }
    297 
    298     // Get camera fps from settings.
    299     int cameraFps = 0;
    300     String fps = sharedPref.getString(keyprefFps,
    301         getString(R.string.pref_fps_default));
    302     String[] fpsValues = fps.split("[ x]+");
    303     if (fpsValues.length == 2) {
    304       try {
    305         cameraFps = Integer.parseInt(fpsValues[0]);
    306       } catch (NumberFormatException e) {
    307         Log.e(TAG, "Wrong camera fps setting: " + fps);
    308       }
    309     }
    310 
    311     // Check capture quality slider flag.
    312     boolean captureQualitySlider = sharedPref.getBoolean(keyprefCaptureQualitySlider,
    313         Boolean.valueOf(getString(R.string.pref_capturequalityslider_default)));
    314 
    315     // Get video and audio start bitrate.
    316     int videoStartBitrate = 0;
    317     String bitrateTypeDefault = getString(
    318         R.string.pref_startvideobitrate_default);
    319     String bitrateType = sharedPref.getString(
    320         keyprefVideoBitrateType, bitrateTypeDefault);
    321     if (!bitrateType.equals(bitrateTypeDefault)) {
    322       String bitrateValue = sharedPref.getString(keyprefVideoBitrateValue,
    323           getString(R.string.pref_startvideobitratevalue_default));
    324       videoStartBitrate = Integer.parseInt(bitrateValue);
    325     }
    326     int audioStartBitrate = 0;
    327     bitrateTypeDefault = getString(R.string.pref_startaudiobitrate_default);
    328     bitrateType = sharedPref.getString(
    329         keyprefAudioBitrateType, bitrateTypeDefault);
    330     if (!bitrateType.equals(bitrateTypeDefault)) {
    331       String bitrateValue = sharedPref.getString(keyprefAudioBitrateValue,
    332           getString(R.string.pref_startaudiobitratevalue_default));
    333       audioStartBitrate = Integer.parseInt(bitrateValue);
    334     }
    335 
    336     // Check statistics display option.
    337     boolean displayHud = sharedPref.getBoolean(keyprefDisplayHud,
    338         Boolean.valueOf(getString(R.string.pref_displayhud_default)));
    339 
    340     boolean tracing = sharedPref.getBoolean(
    341             keyprefTracing, Boolean.valueOf(getString(R.string.pref_tracing_default)));
    342 
    343     // Start AppRTCDemo activity.
    344     Log.d(TAG, "Connecting to room " + roomId + " at URL " + roomUrl);
    345     if (validateUrl(roomUrl)) {
    346       Uri uri = Uri.parse(roomUrl);
    347       Intent intent = new Intent(this, CallActivity.class);
    348       intent.setData(uri);
    349       intent.putExtra(CallActivity.EXTRA_ROOMID, roomId);
    350       intent.putExtra(CallActivity.EXTRA_LOOPBACK, loopback);
    351       intent.putExtra(CallActivity.EXTRA_VIDEO_CALL, videoCallEnabled);
    352       intent.putExtra(CallActivity.EXTRA_VIDEO_WIDTH, videoWidth);
    353       intent.putExtra(CallActivity.EXTRA_VIDEO_HEIGHT, videoHeight);
    354       intent.putExtra(CallActivity.EXTRA_VIDEO_FPS, cameraFps);
    355       intent.putExtra(CallActivity.EXTRA_VIDEO_CAPTUREQUALITYSLIDER_ENABLED,
    356           captureQualitySlider);
    357       intent.putExtra(CallActivity.EXTRA_VIDEO_BITRATE, videoStartBitrate);
    358       intent.putExtra(CallActivity.EXTRA_VIDEOCODEC, videoCodec);
    359       intent.putExtra(CallActivity.EXTRA_HWCODEC_ENABLED, hwCodec);
    360       intent.putExtra(CallActivity.EXTRA_CAPTURETOTEXTURE_ENABLED, captureToTexture);
    361       intent.putExtra(CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED,
    362           noAudioProcessing);
    363       intent.putExtra(CallActivity.EXTRA_AECDUMP_ENABLED, aecDump);
    364       intent.putExtra(CallActivity.EXTRA_OPENSLES_ENABLED, useOpenSLES);
    365       intent.putExtra(CallActivity.EXTRA_AUDIO_BITRATE, audioStartBitrate);
    366       intent.putExtra(CallActivity.EXTRA_AUDIOCODEC, audioCodec);
    367       intent.putExtra(CallActivity.EXTRA_DISPLAY_HUD, displayHud);
    368       intent.putExtra(CallActivity.EXTRA_TRACING, tracing);
    369       intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun);
    370       intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs);
    371 
    372       startActivityForResult(intent, CONNECTION_REQUEST);
    373     }
    374   }
    375 
    376   private boolean validateUrl(String url) {
    377     if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) {
    378       return true;
    379     }
    380 
    381     new AlertDialog.Builder(this)
    382         .setTitle(getText(R.string.invalid_url_title))
    383         .setMessage(getString(R.string.invalid_url_text, url))
    384         .setCancelable(false)
    385         .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
    386             public void onClick(DialogInterface dialog, int id) {
    387               dialog.cancel();
    388             }
    389           }).create().show();
    390     return false;
    391   }
    392 
    393   private final OnClickListener addRoomListener = new OnClickListener() {
    394     @Override
    395     public void onClick(View view) {
    396       String newRoom = roomEditText.getText().toString();
    397       if (newRoom.length() > 0 && !roomList.contains(newRoom)) {
    398         adapter.add(newRoom);
    399         adapter.notifyDataSetChanged();
    400       }
    401     }
    402   };
    403 
    404   private final OnClickListener removeRoomListener = new OnClickListener() {
    405     @Override
    406     public void onClick(View view) {
    407       String selectedRoom = getSelectedItem();
    408       if (selectedRoom != null) {
    409         adapter.remove(selectedRoom);
    410         adapter.notifyDataSetChanged();
    411       }
    412     }
    413   };
    414 
    415   private String getSelectedItem() {
    416     int position = AdapterView.INVALID_POSITION;
    417     if (roomListView.getCheckedItemCount() > 0 && adapter.getCount() > 0) {
    418       position = roomListView.getCheckedItemPosition();
    419       if (position >= adapter.getCount()) {
    420         position = AdapterView.INVALID_POSITION;
    421       }
    422     }
    423     if (position != AdapterView.INVALID_POSITION) {
    424       return adapter.getItem(position);
    425     } else {
    426       return null;
    427     }
    428   }
    429 
    430 }
    431