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}