Пример #1
0
  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder adb = new AlertDialog.Builder(getActivity());
    Settings settings = Settings.getInstance(getActivity());

    String actionName;
    switch (getAction()) {
      case ADD_ACTION:
        actionName = getString(R.string.add);
        break;
      case EDIT_ACTION:
        actionName = getString(R.string.edit);
        break;
      case CONNECT_ACTION:
        actionName = getString(R.string.connect);
        break;
      default:
        throw new RuntimeException("Unknown action " + getAction());
    }
    adb.setPositiveButton(actionName, null);
    adb.setNegativeButton(android.R.string.cancel, null);

    LayoutInflater inflater = LayoutInflater.from(getActivity());
    View view = inflater.inflate(R.layout.dialog_server_edit, null, false);

    TextView titleLabel = (TextView) view.findViewById(R.id.server_edit_name_title);
    mNameEdit = (EditText) view.findViewById(R.id.server_edit_name);
    mHostEdit = (EditText) view.findViewById(R.id.server_edit_host);
    mPortEdit = (EditText) view.findViewById(R.id.server_edit_port);
    mUsernameEdit = (EditText) view.findViewById(R.id.server_edit_username);
    mUsernameEdit.setHint(settings.getDefaultUsername());
    mPasswordEdit = (EditText) view.findViewById(R.id.server_edit_password);

    Server oldServer = getServer();
    if (oldServer != null) {
      mNameEdit.setText(oldServer.getName());
      mHostEdit.setText(oldServer.getHost());
      mPortEdit.setText(String.valueOf(oldServer.getPort()));
      mUsernameEdit.setText(oldServer.getUsername());
      mPasswordEdit.setText(oldServer.getPassword());
    }

    if (shouldIgnoreTitle()) {
      titleLabel.setVisibility(View.GONE);
      mNameEdit.setVisibility(View.GONE);
    }

    // Fixes issues with text colour on light themes with pre-honeycomb devices.
    adb.setInverseBackgroundForced(true);

    adb.setView(view);

    return adb.create();
  }
Пример #2
0
  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) {
    // Push to talk hardware key
    if (settings.isPushToTalk()
        && keyCode == settings.getPushToTalkKey()
        && event.getAction() == KeyEvent.ACTION_UP) {
      setPushToTalk(false);
      return true;
    }

    return super.onKeyUp(keyCode, event);
  }
Пример #3
0
    public UserListAdapter(final Context context, final Runnable visibleUsersChangedCallback) {
      this.context = context;
      this.visibleUsersChangedCallback = visibleUsersChangedCallback;
      this.dbAdapter = new DbAdapter(context);

      // Fetch theme dependent icon
      Settings settings = Settings.getInstance(context);
      chatDrawable =
          getResources()
              .getDrawable(
                  settings.getTheme().equals(Settings.ARRAY_THEME_LIGHTDARK)
                      ? R.drawable.ic_action_chat_light
                      : R.drawable.ic_action_chat_dark);
    }
Пример #4
0
  @Override
  protected void onResume() {
    super.onResume();

    if (settings.getCallMode().equals(Settings.ARRAY_CALL_MODE_VOICE)) setProximityEnabled(true);

    if (mService != null && mService.getCurrentUser() != null)
      updateMuteDeafenMenuItems(mService.isMuted(), mService.isDeafened());

    // Clear chat notifications when activity is re-opened
    if (mService != null && settings.isChatNotifyEnabled()) {
      mService.setActivityVisible(true);
      mService.clearChatNotification();
    }
  }
Пример #5
0
  void updateConnectionState() {
    final int oldState = serviceState;

    switch (state) {
      case MumbleConnectionHost.STATE_CONNECTING:
        serviceState = CONNECTION_STATE_CONNECTING;
        break;
      case MumbleConnectionHost.STATE_CONNECTED:
        settings.addObserver(this);
        serviceState = synced ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_SYNCHRONIZING;
        if (settings.isDeafened()) {
          setDeafened(true);
        } else if (settings.isMuted()) {
          setMuted(true);
        }
        updateFavourites();
        if (synced) {
          // Initialize audio input
          mAudioInput = new AudioInput(this, mProtocol.codec);
          if (settings.isVoiceActivity())
            mAudioInput.startRecording(); // Immediately begin record if using voice activity

          showNotification();
        }
        break;
      case MumbleConnectionHost.STATE_DISCONNECTED:
        settings.deleteObserver(this);
        serviceState = CONNECTION_STATE_DISCONNECTED;
        if (mAudioInput != null) {
          try {
            mAudioInput.stopRecordingAndBlock();
          } catch (InterruptedException e) {
            e.printStackTrace();
          } finally {
            mAudioInput.terminate();
            mAudioInput = null;
          }
        }
        hideNotification();
        break;
      default:
        Assert.fail();
    }

    if (oldState != serviceState) {
      broadcastState();
    }
  }
Пример #6
0
  public AudioOutput(final Context ctx, final AudioOutputHost host) {
    this.settings = new Settings(ctx);
    this.host = host;

    minBufferSize =
        AudioTrack.getMinBufferSize(
            MumbleProtocol.SAMPLE_RATE,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT);

    // Double the buffer size to reduce stuttering.
    final int desiredBufferSize = minBufferSize * 2;

    // Resolve the minimum frame count that fills the minBuffer requirement.
    final int frameCount = (int) Math.ceil((double) desiredBufferSize / MumbleProtocol.FRAME_SIZE);

    bufferSize = frameCount * MumbleProtocol.FRAME_SIZE;

    at =
        new AudioTrack(
            settings.getAudioStream(),
            MumbleProtocol.SAMPLE_RATE,
            AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            bufferSize,
            AudioTrack.MODE_STREAM);

    // Set this here so this.start(); this.shouldRun = false; doesn't
    // result in run() setting shouldRun to true afterwards and continuing
    // running.
    shouldRun = true;
  }
Пример #7
0
  /**
   * Handles activity initialization when the Service has connected.
   *
   * <p>Should be called when there is a reason to believe that the connection might have became
   * valid. The connection MUST be established but other validity criteria may still be unfilled
   * such as server synchronization being complete.
   *
   * <p>The method implements the logic required for making sure that the Connected service is in
   * such a state that it fills all the connection criteria for ChannelList.
   *
   * <p>The method also takes care of making sure that its initialization code is executed only once
   * so calling it several times doesn't cause problems.
   */
  protected void onConnected() {
    // Tell the service that we are now visible.
    mService.setActivityVisible(true);

    // Update user control
    updateUserControlMenuItems();

    // Restore push to talk state, if toggled. Otherwise make sure it's turned off.
    if (settings.isPushToTalk() && mService.isRecording()) {
      if (settings.isPushToTalkToggle() && settings.isPushToTalkButtonShown()) setPushToTalk(true);
      else mService.setPushToTalk(false);
    }

    if (settings.isPushToTalk() && mService.isRecording())
      if (chatTarget != null) {
        listFragment.setChatTarget(chatTarget);
        chatFragment.setChatTarget(chatTarget);
      }
  }
Пример #8
0
  public void addFrameToBuffer(final User u, final PacketDataStream pds, final int flags) {
    AudioUser user = users.get(u);
    if (user == null) {
      user = new AudioUser(u, settings.isJitterBuffer());
      users.put(u, user);
      // Don't add the user to userPackets yet. The collection should
      // have only users with ready frames. Since this method is
      // called only from the TCP connection thread it will never
      // create a new AudioUser while a previous one is still decoding.
    }

    user.addFrameToBuffer(pds, packetReadyHandler);
  }
Пример #9
0
  /** Connects to the passed 'Server' object. */
  public void connectToServer(Server server) {
    this.connectedServer = server;

    String plumbleVersion;
    try {
      plumbleVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
    } catch (NameNotFoundException e) {
      plumbleVersion = "???";
    }
    final String certificatePath = settings.getCertificatePath();
    final String certificatePassword = settings.getCertificatePassword();

    mProtocolHost = new ServiceProtocolHost();
    mConnectionHost = new ServiceConnectionHost();
    mAudioHost = new ServiceAudioOutputHost();

    mClient =
        new MumbleConnection(
            mConnectionHost,
            plumbleVersion,
            connectedServer.getHost(),
            connectedServer.getPort(),
            connectedServer.getUsername(),
            connectedServer.getPassword(),
            certificatePath,
            certificatePassword,
            settings.isTcpForced(),
            settings.isOpusDisabled());

    mProtocol = new MumbleProtocol(mProtocolHost, mAudioHost, mClient, getApplicationContext());

    mClientThread = mClient.start(mProtocol);

    // Acquire wake lock
    wakeLock.acquire();

    // Enable TTS
    tts = new TextToSpeech(this, this);
  }
Пример #10
0
  @Override
  public boolean onKeyDown(final int keyCode, final KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
      final AlertDialog.Builder b = new AlertDialog.Builder(this);
      b.setTitle(R.string.disconnect);
      b.setMessage(R.string.disconnectSure);
      b.setPositiveButton(android.R.string.yes, onDisconnectConfirm);
      b.setNegativeButton(android.R.string.no, null);
      b.show();

      return true;
    }

    // Push to talk hardware key
    if (settings.isPushToTalk()
        && keyCode == settings.getPushToTalkKey()
        && event.getAction() == KeyEvent.ACTION_DOWN) {
      setPushToTalk(true);
      return true;
    }

    return super.onKeyDown(keyCode, event);
  }
Пример #11
0
  public void setPushToTalk(final boolean state) {
    if (mProtocol == null || mProtocol.currentUser == null) return;

    Assert.assertTrue(
        "Push to talk not on, but setPushToTalk called!", !settings.isVoiceActivity());

    if (state) {
      mAudioHost.setTalkState(getCurrentUser(), AudioOutputHost.STATE_TALKING);
      mAudioInput.startRecording();
    } else {
      mAudioHost.setTalkState(getCurrentUser(), AudioOutputHost.STATE_PASSIVE);
      mAudioInput.stopRecording();
    }
  }
Пример #12
0
  // Settings observer
  @Override
  public void update(Observable observable, Object data) {
    Settings settings = (Settings) observable;

    if (data.equals(Settings.OBSERVER_KEY_ALL)) {
      // Create PTT overlay
      dismissPTTOverlay();
      if (settings.isPushToTalk()
          && !settings.getHotCorner().equals(Settings.ARRAY_HOT_CORNER_NONE)) {
        createPTTOverlay();
      }

      // Handle voice activity
      try {
        mAudioInput
            .stopRecordingAndBlock(); // We block because we want to wait before restarting
                                      // recording to avoid a concurrent modificatione exception.
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        if (settings.isVoiceActivity()) mAudioInput.startRecording();
      }
    }
  }
Пример #13
0
  @Override
  protected void onPause() {
    super.onPause();

    if (settings.getCallMode().equals(Settings.ARRAY_CALL_MODE_VOICE)) setProximityEnabled(false);

    if (mService != null) {
      mService.setActivityVisible(false);

      // Turn off push to talk when rotating so it doesn't get stuck on, except if it's in toggled
      // state.
      // if(settings.isPushToTalk() && !mTalkToggleBox.isChecked()) {
      //	mService.setRecording(false);
      // }
    }
  }
Пример #14
0
  /**
   * Creates a system overlay that allows the user to touch the corner of the screen to push to
   * talk.
   */
  public void createPTTOverlay() {
    WindowManager.LayoutParams pttParams =
        new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);
    String hotCorner = settings.getHotCorner();
    if (hotCorner.equals(Settings.ARRAY_HOT_CORNER_TOP_LEFT)) {
      pttParams.gravity = Gravity.LEFT | Gravity.TOP;
    } else if (hotCorner.equals(Settings.ARRAY_HOT_CORNER_BOTTOM_LEFT)) {
      pttParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
    } else if (hotCorner.equals(Settings.ARRAY_HOT_CORNER_TOP_RIGHT)) {
      pttParams.gravity = Gravity.RIGHT | Gravity.TOP;
    } else if (hotCorner.equals(Settings.ARRAY_HOT_CORNER_BOTTOM_RIGHT)) {
      pttParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
    }
    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    overlayView = inflater.inflate(R.layout.overlay, null);
    final Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
    overlayView.setOnTouchListener(
        new View.OnTouchListener() {

          @Override
          public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
              setPushToTalk(true);
              // Vibrate to provide haptic feedback
              vibrator.vibrate(10);
              overlayView.setBackgroundColor(0xAA33b5e5);
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
              setPushToTalk(false);
              overlayView.setBackgroundColor(0);
            }
            return false;
          }
        });

    // Add layout to window manager
    wm.addView(overlayView, pttParams);
  }
Пример #15
0
  @Override
  public void onCreate() {
    super.onCreate();

    // Make sure our notification is gone.
    hideNotification();

    settings = Settings.getInstance(this);

    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "plumbleLock");

    Log.i(Globals.LOG_TAG, "MumbleService: Created");
    serviceState = CONNECTION_STATE_DISCONNECTED;

    chatFormatter = new PlumbleChatFormatter(this);

    dbAdapter = new DbAdapter(this);
    dbAdapter.open();
  }
Пример #16
0
  /**
   * Handles activity initialization when the Service has connected.
   *
   * <p>Should be called when there is a reason to believe that the connection might have became
   * valid. The connection MUST be established but other validity criteria may still be unfilled
   * such as server synchronization being complete.
   *
   * <p>The method implements the logic required for making sure that the Connected service is in
   * such a state that it fills all the connection criteria for ChannelList.
   *
   * <p>The method also takes care of making sure that its initialization code is executed only once
   * so calling it several times doesn't cause problems.
   */
  protected void onConnected() {
    // Tell the service that we are now visible.
    mService.setActivityVisible(true);

    // Update user control
    updateUserControlMenuItems();

    // Restore push to talk state, if toggled. Otherwise make sure it's turned off.
    if (settings.isPushToTalk() && mService.isRecording()) {
      if (settings.isPushToTalkToggle() && settings.isPushToTalkButtonShown()) setPushToTalk(true);
      else mService.setPushToTalk(false);
    }

    if (settings.isPushToTalk() && mService.isRecording())
      if (chatTarget != null) {
        listFragment.setChatTarget(chatTarget);
        chatFragment.setChatTarget(chatTarget);
      }

    // Showcase hints
    List<ShowcaseView> showcaseViews = new ArrayList<ShowcaseView>();
    if (settings.isPushToTalk() && settings.isPushToTalkButtonShown()) {
      ConfigOptions pttConfig = new ConfigOptions();
      pttConfig.shotType = ShowcaseView.TYPE_ONE_SHOT;
      pttConfig.showcaseId = Globals.SHOWCASE_PUSH_TO_TALK;
      showcaseViews.add(
          ShowcaseView.insertShowcaseView(
              pttView, this, R.string.hint_ptt, R.string.hint_ptt_summary, pttConfig));
    }

    if (mViewPager != null) {
      ConfigOptions switcherConfig = new ConfigOptions();
      switcherConfig.shotType = ShowcaseView.TYPE_ONE_SHOT;
      switcherConfig.showcaseId = Globals.SHOWCASE_SWITCHER;
      showcaseViews.add(
          ShowcaseView.insertShowcaseView(
              ShowcaseView.ITEM_ACTION_HOME,
              0,
              this,
              R.string.hint_switching,
              R.string.hint_switching_summary,
              switcherConfig));
    }

    ShowcaseViewQueue queue = new ShowcaseViewQueue(showcaseViews);
    queue.queueNext();
  }
Пример #17
0
 private void updatePTTConfiguration() {
   pttView.setVisibility(
       settings.isPushToTalk() && settings.isPushToTalkButtonShown() ? View.VISIBLE : View.GONE);
 }
Пример #18
0
  @Override
  public void onCreate(Bundle savedInstanceState) {
    settings = Settings.getInstance(this);
    settings.addObserver(this);

    // Use theme from settings
    int theme = 0;
    if (settings.getTheme().equals(Settings.ARRAY_THEME_LIGHTDARK)) {
      theme = R.style.Theme_Sherlock_Light_DarkActionBar;
    } else if (settings.getTheme().equals(Settings.ARRAY_THEME_DARK)) {
      theme = R.style.Theme_Sherlock;
    }
    setTheme(theme);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_channel);

    // Bind to service
    Intent serviceIntent = new Intent(this, MumbleService.class);
    bindService(serviceIntent, conn, 0);

    // Register bluetooth SCO monitor
    registerReceiver(
        bluetoothReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));

    // Handle differences in CallMode

    String callMode = settings.getCallMode();
    setVolumeControlStream(
        Settings.ARRAY_CALL_MODE_SPEAKER.equals(callMode)
            ? AudioManager.STREAM_MUSIC
            : AudioManager.STREAM_VOICE_CALL);

    // Set up proximity sensor
    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    proximityLock = powerManager.newWakeLock(PROXIMITY_SCREEN_OFF_WAKE_LOCK, Globals.LOG_TAG);

    // Set up PTT button.

    mTalkButton = (Button) findViewById(R.id.pushtotalk);
    pttView = findViewById(R.id.pushtotalk_view);
    mTalkButton.setOnTouchListener(
        new OnTouchListener() {

          private static final int TOGGLE_INTERVAL =
              250; // 250ms is the interval needed to toggle push to talk.
          private long lastTouch = 0;

          @Override
          public boolean onTouch(View v, MotionEvent event) {
            if (mService == null) {
              return false;
            }

            if (event.getAction() == MotionEvent.ACTION_DOWN && !settings.isPushToTalkToggle()) {
              setPushToTalk(true);
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
              if (settings.isPushToTalkToggle()) setPushToTalk(!mService.isRecording());
              else {
                if (System.currentTimeMillis() - lastTouch <= TOGGLE_INTERVAL) {
                  // Do nothing. We leave the push to talk on, as it has toggled.
                } else {
                  setPushToTalk(false);
                  lastTouch = System.currentTimeMillis();
                }
              }
            }

            return true; // We return true so that the selector that changes the background does not
            // fire.
          }
        });

    updatePTTConfiguration();

    mViewPager = (ViewPager) findViewById(R.id.pager);
    FragmentManager fragmentManager = getSupportFragmentManager();

    listFragment = (ChannelListFragment) fragmentManager.findFragmentByTag(LIST_FRAGMENT_TAG);
    chatFragment = (ChannelChatFragment) fragmentManager.findFragmentByTag(CHAT_FRAGMENT_TAG);

    FragmentTransaction remove = fragmentManager.beginTransaction();
    if (listFragment == null) listFragment = new ChannelListFragment();
    else remove.remove(listFragment);

    if (chatFragment == null) chatFragment = new ChannelChatFragment();
    else remove.remove(chatFragment);

    if (!remove.isEmpty()) {
      remove.commit();
      fragmentManager.executePendingTransactions();
    }

    if (mViewPager != null) {
      // Set up the ViewPager with the sections adapter.
      mViewPager.setOnPageChangeListener(
          new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {
              // Hide keyboard if moving to channel list.
              if (arg0 == 0) {
                InputMethodManager imm =
                    (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mViewPager.getApplicationWindowToken(), 0);
              }
              // Update indicator
              channelsIndicator.setVisibility(arg0 == 0 ? View.VISIBLE : View.INVISIBLE);
              chatIndicator.setVisibility(arg0 == 1 ? View.VISIBLE : View.INVISIBLE);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {}

            @Override
            public void onPageScrollStateChanged(int arg0) {}
          });

      // Set up tabs
      getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);

      View channelTabView = getLayoutInflater().inflate(R.layout.channel_tab_view, null);
      channelsIndicator = channelTabView.findViewById(R.id.tab_channels_indicator);
      chatIndicator = channelTabView.findViewById(R.id.tab_chat_indicator);

      ImageButton channelsButton = (ImageButton) channelTabView.findViewById(R.id.tab_channels);
      ImageButton chatButton = (ImageButton) channelTabView.findViewById(R.id.tab_chat);
      channelsButton.setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              mViewPager.setCurrentItem(0, true);
            }
          });
      chatButton.setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              mViewPager.setCurrentItem(1, true);
            }
          });

      getSupportActionBar().setCustomView(channelTabView);
      // Setup a pager that will return a fragment for each of the two primary sections of the app.
      mSectionsPagerAdapter =
          new PlumbleSectionsPagerAdapter(
              this, getSupportFragmentManager(), listFragment, chatFragment);
      mViewPager.setAdapter(mSectionsPagerAdapter);

    } else {
      // Create tablet UI
      leftSplit = findViewById(R.id.left_split);
      rightSplit = findViewById(R.id.right_split);
      fragmentManager
          .beginTransaction()
          .add(R.id.chat_fragment, chatFragment, CHAT_FRAGMENT_TAG)
          .add(R.id.list_fragment, listFragment, LIST_FRAGMENT_TAG)
          .commit();
    }

    if (savedInstanceState != null) {
      chatTarget = (User) savedInstanceState.getParcelable(SAVED_STATE_CHAT_TARGET);
    }
  }
Пример #19
0
 public void setDeafened(final boolean state) {
   if (mAudioHost != null && mProtocol != null && mProtocol.currentUser != null) {
     mAudioHost.setSelfDeafened(mProtocol.currentUser, state);
     settings.setMutedAndDeafened(state, state);
   }
 }