1/* 2 * Copyright (c) 2013 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 11package org.webrtc.webrtcdemo; 12 13import android.app.ActionBar.Tab; 14import android.app.ActionBar.TabListener; 15import android.app.ActionBar; 16import android.app.Activity; 17import android.app.Fragment; 18import android.app.FragmentTransaction; 19import android.content.pm.ActivityInfo; 20import android.media.AudioManager; 21import android.os.Bundle; 22import android.os.Handler; 23import android.view.KeyEvent; 24import android.view.Menu; 25import android.view.MenuInflater; 26import android.view.MenuItem; 27import android.view.WindowManager; 28 29public class WebRTCDemo extends Activity implements MenuStateProvider { 30 31 // From http://developer.android.com/guide/topics/ui/actionbar.html 32 public static class TabListener<T extends Fragment> 33 implements ActionBar.TabListener { 34 private Fragment fragment; 35 private final Activity activity; 36 private final String tag; 37 private final Class<T> instance; 38 private final Bundle args; 39 40 public TabListener(Activity activity, String tag, Class<T> clz) { 41 this(activity, tag, clz, null); 42 } 43 44 public TabListener(Activity activity, String tag, Class<T> clz, 45 Bundle args) { 46 this.activity = activity; 47 this.tag = tag; 48 this.instance = clz; 49 this.args = args; 50 } 51 52 public void onTabSelected(Tab tab, FragmentTransaction ft) { 53 // Check if the fragment is already initialized 54 if (fragment == null) { 55 // If not, instantiate and add it to the activity 56 fragment = Fragment.instantiate(activity, instance.getName(), args); 57 ft.add(android.R.id.content, fragment, tag); 58 } else { 59 // If it exists, simply attach it in order to show it 60 ft.attach(fragment); 61 } 62 } 63 64 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 65 if (fragment != null) { 66 // Detach the fragment, because another one is being attached 67 ft.detach(fragment); 68 } 69 } 70 71 public void onTabReselected(Tab tab, FragmentTransaction ft) { 72 // User selected the already selected tab. Do nothing. 73 } 74 } 75 76 private NativeWebRtcContextRegistry contextRegistry = null; 77 private MediaEngine mediaEngine = null; 78 private Handler handler; 79 public MediaEngine getEngine() { return mediaEngine; } 80 81 @Override 82 public void onCreate(Bundle savedInstanceState) { 83 super.onCreate(savedInstanceState); 84 85 // Global settings. 86 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 87 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 88 89 // State. 90 // Must be instantiated before MediaEngine. 91 contextRegistry = new NativeWebRtcContextRegistry(); 92 contextRegistry.register(this); 93 94 // Load all settings dictated in xml. 95 mediaEngine = new MediaEngine(this); 96 mediaEngine.setRemoteIp(getResources().getString(R.string.loopbackIp)); 97 mediaEngine.setTrace(getResources().getBoolean( 98 R.bool.trace_enabled_default)); 99 100 mediaEngine.setAudio(getResources().getBoolean( 101 R.bool.audio_enabled_default)); 102 mediaEngine.setAudioCodec(mediaEngine.getIsacIndex()); 103 mediaEngine.setAudioRxPort(getResources().getInteger( 104 R.integer.aRxPortDefault)); 105 mediaEngine.setAudioTxPort(getResources().getInteger( 106 R.integer.aTxPortDefault)); 107 mediaEngine.setSpeaker(getResources().getBoolean( 108 R.bool.speaker_enabled_default)); 109 mediaEngine.setDebuging(getResources().getBoolean( 110 R.bool.apm_debug_enabled_default)); 111 112 mediaEngine.setReceiveVideo(getResources().getBoolean( 113 R.bool.video_receive_enabled_default)); 114 mediaEngine.setSendVideo(getResources().getBoolean( 115 R.bool.video_send_enabled_default)); 116 mediaEngine.setVideoCodec(getResources().getInteger( 117 R.integer.video_codec_default)); 118 // TODO(hellner): resolutions should probably be in the xml as well. 119 mediaEngine.setResolutionIndex(MediaEngine.numberOfResolutions() - 2); 120 mediaEngine.setVideoTxPort(getResources().getInteger( 121 R.integer.vTxPortDefault)); 122 mediaEngine.setVideoRxPort(getResources().getInteger( 123 R.integer.vRxPortDefault)); 124 mediaEngine.setNack(getResources().getBoolean(R.bool.nack_enabled_default)); 125 mediaEngine.setViewSelection(getResources().getInteger( 126 R.integer.defaultView)); 127 128 // Create action bar with all tabs. 129 ActionBar actionBar = getActionBar(); 130 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 131 actionBar.setDisplayShowTitleEnabled(false); 132 133 Tab tab = actionBar.newTab() 134 .setText("Main") 135 .setTabListener(new TabListener<MainMenuFragment>( 136 this, "main", MainMenuFragment.class)); 137 actionBar.addTab(tab); 138 139 tab = actionBar.newTab() 140 .setText("Settings") 141 .setTabListener(new TabListener<SettingsMenuFragment>( 142 this, "Settings", SettingsMenuFragment.class)); 143 actionBar.addTab(tab); 144 145 tab = actionBar.newTab() 146 .setText("Video") 147 .setTabListener(new TabListener<VideoMenuFragment>( 148 this, "video", VideoMenuFragment.class)); 149 actionBar.addTab(tab); 150 151 tab = actionBar.newTab() 152 .setText("Audio") 153 .setTabListener(new TabListener<AudioMenuFragment>( 154 this, "Audio", AudioMenuFragment.class)); 155 actionBar.addTab(tab); 156 157 enableTimedStartStop(); 158 159 // Hint that voice call audio stream should be used for hardware volume 160 // controls. 161 setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); 162 } 163 164 @Override 165 public boolean onCreateOptionsMenu(Menu menu) { 166 MenuInflater inflater = getMenuInflater(); 167 inflater.inflate(R.menu.main_activity_actions, menu); 168 return super.onCreateOptionsMenu(menu); 169 } 170 171 @Override 172 public boolean onOptionsItemSelected(MenuItem item) { 173 // Handle presses on the action bar items 174 switch (item.getItemId()) { 175 case R.id.action_exit: 176 MainMenuFragment main = (MainMenuFragment)getFragmentManager() 177 .findFragmentByTag("main"); 178 main.stopAll(); 179 finish(); 180 return true; 181 default: 182 return super.onOptionsItemSelected(item); 183 } 184 } 185 186 @Override 187 public void onDestroy() { 188 disableTimedStartStop(); 189 mediaEngine.dispose(); 190 contextRegistry.unRegister(); 191 super.onDestroy(); 192 } 193 194 @Override 195 public boolean onKeyDown(int keyCode, KeyEvent event) { 196 if (keyCode == KeyEvent.KEYCODE_BACK) { 197 // Prevent app from running in the background. 198 MainMenuFragment main = (MainMenuFragment)getFragmentManager() 199 .findFragmentByTag("main"); 200 main.stopAll(); 201 finish(); 202 return true; 203 } 204 return super.onKeyDown(keyCode, event); 205 } 206 207 private int getCallRestartPeriodicity() { 208 return getResources().getInteger(R.integer.call_restart_periodicity_ms); 209 } 210 211 // Thread repeatedly calling start/stop. 212 void enableTimedStartStop() { 213 if (getCallRestartPeriodicity() > 0) { 214 // Periodicity == 0 <-> Disabled. 215 handler = new Handler(); 216 handler.postDelayed(startOrStopCallback, getCallRestartPeriodicity()); 217 } 218 } 219 220 void disableTimedStartStop() { 221 if (handler != null) { 222 handler.removeCallbacks(startOrStopCallback); 223 } 224 } 225 226 private Runnable startOrStopCallback = new Runnable() { 227 public void run() { 228 MainMenuFragment main = (MainMenuFragment)getFragmentManager() 229 .findFragmentByTag("main"); 230 main.toggleStart(); 231 handler.postDelayed(startOrStopCallback, getCallRestartPeriodicity()); 232 } 233 }; 234}