Java tutorial
/* * Copyright (c) 2005-2018, BearWare.dk * * Contact Information: * * Bjoern D. Rasmussen * Kirketoften 5 * DK-8260 Viby J * Denmark * Email: contact@bearware.dk * Phone: +45 20 20 54 59 * Web: http://www.bearware.dk * * This source code is part of the TeamTalk SDK owned by * BearWare.dk. Use of this file, or its compiled unit, requires a * TeamTalk SDK License Key issued by BearWare.dk. * * The TeamTalk SDK License Agreement along with its Terms and * Conditions are outlined in the file License.txt included with the * TeamTalk SDK distribution. * */ package dk.bearware.gui; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.Locale; import java.util.List; import java.util.Vector; import dk.bearware.BannedUser; import dk.bearware.Channel; import dk.bearware.ClientErrorMsg; import dk.bearware.ClientFlag; import dk.bearware.ClientStatistics; import dk.bearware.DesktopInput; import dk.bearware.FileTransfer; import dk.bearware.MediaFileInfo; import dk.bearware.RemoteFile; import dk.bearware.ServerProperties; import dk.bearware.SoundLevel; import dk.bearware.TeamTalkBase; import dk.bearware.TextMessage; import dk.bearware.TextMsgType; import dk.bearware.User; import dk.bearware.UserAccount; import dk.bearware.UserRight; import dk.bearware.UserState; import dk.bearware.data.Permissions; import dk.bearware.events.ClientListener; import dk.bearware.events.CommandListener; import dk.bearware.events.ConnectionListener; import dk.bearware.events.UserListener; import dk.bearware.backend.OnVoiceTransmissionToggleListener; import dk.bearware.backend.TeamTalkConnection; import dk.bearware.backend.TeamTalkConnectionListener; import dk.bearware.backend.TeamTalkConstants; import dk.bearware.backend.TeamTalkService; import dk.bearware.data.FileListAdapter; import dk.bearware.data.MediaAdapter; import dk.bearware.data.Preferences; import dk.bearware.data.ServerEntry; import dk.bearware.data.TextMessageAdapter; import dk.bearware.data.TTSWrapper; import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Color; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.SoundPool; import android.os.Build; import android.os.Bundle; import android.os.CountDownTimer; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Vibrator; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.ListFragment; import android.support.v4.view.ViewPager; import android.text.method.SingleLineTransformationMethod; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.inputmethod.InputMethodManager; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends FragmentActivity implements TeamTalkConnectionListener, ConnectionListener, CommandListener, UserListener, ClientListener, OnItemClickListener, OnItemLongClickListener, OnMenuItemClickListener, OnVoiceTransmissionToggleListener { /** * The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the sections. We use a * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will keep every loaded fragment in memory. * If this becomes too memory intensive, it may be best to switch to a * {@link android.support.v4.app.FragmentStatePagerAdapter}. */ SectionsPagerAdapter mSectionsPagerAdapter; /** * The {@link ViewPager} that will host the section contents. */ ViewPager mViewPager; public static final String TAG = "bearware"; public final int REQUEST_EDITCHANNEL = 1, REQUEST_NEWCHANNEL = 2, REQUEST_EDITUSER = 3, REQUEST_SELECT_FILE = 4; // The channel currently being displayed Channel curchannel; // The channel we're currenlty in Channel mychannel; SparseArray<CmdComplete> activecmds = new SparseArray<CmdComplete>(); ChannelListAdapter channelsAdapter; FileListAdapter filesAdapter; TextMessageAdapter textmsgAdapter; MediaAdapter mediaAdapter; TTSWrapper ttsWrapper = null; AccessibilityAssistant accessibilityAssistant; AudioManager audioManager; SoundPool audioIcons; ComponentName mediaButtonEventReceiver; NotificationManager notificationManager; WakeLock wakeLock; boolean restarting; static final String MESSAGE_NOTIFICATION_TAG = "incoming_message"; final int SOUND_VOICETXON = 1, SOUND_VOICETXOFF = 2, SOUND_USERMSG = 3, SOUND_CHANMSG = 4, SOUND_BCASTMSG = 5, SOUND_SERVERLOST = 6, SOUND_FILESUPDATE = 7, SOUND_VOXON = 8, SOUND_VOXOFF = 9, SOUND_TXREADY = 10, SOUND_TXSTOP = 11, SOUND_USERJOIN = 12, SOUND_USERLEFT = 13; SparseIntArray sounds = new SparseIntArray(); public ChannelListAdapter getChannelsAdapter() { return channelsAdapter; } public FileListAdapter getFilesAdapter() { return filesAdapter; } public TextMessageAdapter getTextMessagesAdapter() { return textmsgAdapter; } public MediaAdapter getMediaAdapter() { return mediaAdapter; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String serverName = getIntent().getStringExtra(ServerEntry.KEY_SERVERNAME); if ((serverName != null) && !serverName.isEmpty()) setTitle(serverName); getActionBar().setDisplayHomeAsUpEnabled(true); restarting = (savedInstanceState != null); accessibilityAssistant = new AccessibilityAssistant(this); audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mediaButtonEventReceiver = new ComponentName(getPackageName(), MediaButtonEventReceiver.class.getName()); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); wakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE)) .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); wakeLock.setReferenceCounted(false); channelsAdapter = new ChannelListAdapter(this.getBaseContext()); filesAdapter = new FileListAdapter(this, this, accessibilityAssistant); textmsgAdapter = new TextMessageAdapter(this.getBaseContext(), accessibilityAssistant); mediaAdapter = new MediaAdapter(this.getBaseContext()); // Create the adapter that will return a fragment for each of the five // primary sections of the app. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setOnPageChangeListener(mSectionsPagerAdapter); setupButtons(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { final MediaPlayer mMediaPlayer; mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.silence); mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { mMediaPlayer.release(); } }); mMediaPlayer.start(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean isEditable = curchannel != null; boolean isJoinable = (ttclient != null) && (curchannel != null) && (ttclient.getMyChannelID() != curchannel.nChannelID); boolean isMyChannel = (ttclient != null) && (curchannel != null) && (ttclient.getMyChannelID() == curchannel.nChannelID); menu.findItem(R.id.action_edit).setEnabled(isEditable).setVisible(isEditable); menu.findItem(R.id.action_join).setEnabled(isJoinable).setVisible(isJoinable); menu.findItem(R.id.action_upload).setEnabled(isMyChannel).setVisible(isMyChannel); menu.findItem(R.id.action_stream).setEnabled(isMyChannel).setVisible(isMyChannel); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_join: { if (curchannel != null) joinChannel(curchannel); } break; case R.id.action_upload: { if (Permissions.setupPermission(getBaseContext(), this, Permissions.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)) { startActivityForResult(new Intent(this, FilePickerActivity.class), REQUEST_SELECT_FILE); } } break; case R.id.action_stream: { int flags = ttclient.getFlags(); if ((flags & ClientFlag.CLIENT_STREAM_AUDIO) == ClientFlag.CLIENT_STREAM_AUDIO || (flags & ClientFlag.CLIENT_STREAM_VIDEO) == ClientFlag.CLIENT_STREAM_VIDEO) { ttclient.stopStreamingMediaFileToChannel(); } else { Intent intent = new Intent(MainActivity.this, StreamMediaActivity.class); startActivity(intent); } } break; case R.id.action_edit: { if (curchannel != null) editChannelProperties(curchannel); } break; case R.id.action_newchannel: { Intent intent = new Intent(MainActivity.this, ChannelPropActivity.class); int parent_chan_id = ttclient.getRootChannelID(); if (curchannel != null) parent_chan_id = curchannel.nChannelID; intent = intent.putExtra(ChannelPropActivity.EXTRA_PARENTID, parent_chan_id); startActivityForResult(intent, REQUEST_NEWCHANNEL); } break; case R.id.action_settings: { Intent intent = new Intent(MainActivity.this, PreferencesActivity.class); startActivity(intent); break; } case android.R.id.home: { if (filesAdapter.getActiveTransfersCount() > 0) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setMessage(R.string.disconnect_alert); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { filesAdapter.cancelAllTransfers(); finish(); } }); alert.setNegativeButton(android.R.string.cancel, null); alert.show(); } else { finish(); } break; } default: return super.onOptionsItemSelected(item); } return true; } CountDownTimer stats_timer = null; TeamTalkConnection mConnection; TeamTalkService ttservice; TeamTalkBase ttclient; @Override protected void onStart() { super.onStart(); if (ttsWrapper == null) ttsWrapper = TTSWrapper.getInstance(this); if (mConnection == null) mConnection = new TeamTalkConnection(this); if (!mConnection.isBound()) { // Bind to LocalService Intent intent = new Intent(getApplicationContext(), TeamTalkService.class); Log.d(TAG, "Binding TeamTalk service"); if (!bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) Log.e(TAG, "Failed to bind to TeamTalk service"); } else { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); int mastervol = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_MASTERVOLUME, SoundLevel.SOUND_VOLUME_DEFAULT); int gain = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_MICROPHONEGAIN, SoundLevel.SOUND_GAIN_DEFAULT); int voxlevel = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_VOICEACTIVATION_LEVEL, 5); boolean voxState = ttservice.isVoiceActivationEnabled(); boolean txState = ttservice.isVoiceTransmitting(); // only set volume and gain if tt-instance hasn't already been configured if (ttclient.getSoundOutputVolume() != mastervol) ttclient.setSoundOutputVolume(mastervol); if (ttclient.getSoundInputGainLevel() != gain) ttclient.setSoundInputGainLevel(gain); if (ttclient.getVoiceActivationLevel() != voxlevel) ttclient.setVoiceActivationLevel(voxlevel); adjustMuteButton((ImageButton) findViewById(R.id.speakerBtn)); adjustVoxState(voxState, voxState ? voxlevel : gain); adjustTxState(txState); TextView volLevel = (TextView) findViewById(R.id.vollevel_text); volLevel.setText(Utils.refVolumeToPercent(mastervol) + "%"); volLevel.setContentDescription(getString(R.string.speaker_volume_description, volLevel.getText())); } } @Override protected void onResume() { super.onResume(); if (audioIcons != null) audioIcons.release(); sounds.clear(); audioIcons = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); audioManager.setMode(prefs.getBoolean(Preferences.PREF_SOUNDSYSTEM_VOICEPROCESSING, false) ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_NORMAL); audioManager.setSpeakerphoneOn(prefs.getBoolean(Preferences.PREF_SOUNDSYSTEM_SPEAKERPHONE, false)); if (prefs.getBoolean("server_lost_audio_icon", true)) { sounds.put(SOUND_SERVERLOST, audioIcons.load(getApplicationContext(), R.raw.serverlost, 1)); } if (prefs.getBoolean("rx_tx_audio_icon", true)) { sounds.put(SOUND_VOICETXON, audioIcons.load(getApplicationContext(), R.raw.on, 1)); sounds.put(SOUND_VOICETXOFF, audioIcons.load(getApplicationContext(), R.raw.off, 1)); } if (prefs.getBoolean("personal_message_audio_icon", true)) { sounds.put(SOUND_USERMSG, audioIcons.load(getApplicationContext(), R.raw.user_message, 1)); } if (prefs.getBoolean("channel_message_audio_icon", true)) { sounds.put(SOUND_CHANMSG, audioIcons.load(getApplicationContext(), R.raw.channel_message, 1)); } if (prefs.getBoolean("broadcast_message_audio_icon", true)) { sounds.put(SOUND_BCASTMSG, audioIcons.load(getApplicationContext(), R.raw.channel_message, 1)); } if (prefs.getBoolean("files_updated_audio_icon", true)) { sounds.put(SOUND_FILESUPDATE, audioIcons.load(getApplicationContext(), R.raw.fileupdate, 1)); } if (prefs.getBoolean("voiceact_triggered_icon", true)) { sounds.put(SOUND_VOXON, audioIcons.load(getApplicationContext(), R.raw.voiceact_on, 1)); sounds.put(SOUND_VOXOFF, audioIcons.load(getApplicationContext(), R.raw.voiceact_off, 1)); } if (prefs.getBoolean("transmitready_icon", true)) { sounds.put(SOUND_TXREADY, audioIcons.load(getApplicationContext(), R.raw.txqueue_start, 1)); sounds.put(SOUND_TXSTOP, audioIcons.load(getApplicationContext(), R.raw.txqueue_stop, 1)); } if (prefs.getBoolean("userjoin_icon", true)) { sounds.put(SOUND_USERJOIN, audioIcons.load(getApplicationContext(), R.raw.user_join, 1)); } if (prefs.getBoolean("userleft_icon", true)) { sounds.put(SOUND_USERLEFT, audioIcons.load(getApplicationContext(), R.raw.user_left, 1)); } getTextMessagesAdapter().showLogMessages(prefs.getBoolean("show_log_messages", true)); getWindow().getDecorView().setKeepScreenOn(prefs.getBoolean("keep_screen_on_checkbox", false)); createStatusTimer(); } @Override protected void onPause() { super.onPause(); if (stats_timer != null) { stats_timer.cancel(); stats_timer = null; } } @Override protected void onStop() { super.onStop(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); if (mConnection.isBound()) { SharedPreferences.Editor editor = prefs.edit(); editor.putInt(Preferences.PREF_SOUNDSYSTEM_MASTERVOLUME, ttclient.getSoundOutputVolume()); editor.putInt(Preferences.PREF_SOUNDSYSTEM_MICROPHONEGAIN, ttclient.getSoundInputGainLevel()); editor.putInt(Preferences.PREF_SOUNDSYSTEM_VOICEACTIVATION_LEVEL, ttclient.getVoiceActivationLevel()); editor.apply(); } // Cleanup resources if (isFinishing()) { if (audioIcons != null) { audioIcons.release(); audioIcons = null; } if (ttsWrapper != null) { ttsWrapper.shutdown(); ttsWrapper = null; } // Unbind from the service if (mConnection.isBound()) { Log.d(TAG, "Unbinding TeamTalk service"); onServiceDisconnected(ttservice); ttservice.disablePhoneCallReaction(); ttservice.resetState(); unbindService(mConnection); mConnection.setBound(false); } notificationManager.cancelAll(); } } @Override protected void onDestroy() { super.onDestroy(); // Unbind from the service if (mConnection.isBound()) { Log.d(TAG, "Unbinding TeamTalk service"); onServiceDisconnected(ttservice); unbindService(mConnection); mConnection.setBound(false); } Log.d(TAG, "Activity destroyed " + this.hashCode()); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == REQUEST_SELECT_FILE) && (resultCode == RESULT_OK)) { String path = data.getStringExtra(FilePickerActivity.SELECTED_FILE); String remoteName = filesAdapter.getRemoteName(path); if (remoteName != null) { Toast.makeText(this, getString(R.string.remote_file_exists, remoteName), Toast.LENGTH_LONG).show(); } else if (ttclient.doSendFile(curchannel.nChannelID, path) <= 0) { Toast.makeText(this, getString(R.string.upload_failed, path), Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, R.string.upload_started, Toast.LENGTH_SHORT).show(); } } } ChannelsSectionFragment channelsFragment; ChatSectionFragment chatFragment; VidcapSectionFragment vidcapFragment; MediaSectionFragment mediaFragment; FilesSectionFragment filesFragment; /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the sections/tabs/pages. */ public class SectionsPagerAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener { public static final int CHANNELS_PAGE = 0, CHAT_PAGE = 1, MEDIA_PAGE = 2, FILES_PAGE = 3, PAGE_COUNT = 4; public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { // getItem is called to instantiate the fragment for the given page. switch (position) { default: case CHANNELS_PAGE: { channelsFragment = new ChannelsSectionFragment(); return channelsFragment; } case CHAT_PAGE: { chatFragment = new ChatSectionFragment(); return chatFragment; } case MEDIA_PAGE: { mediaFragment = new MediaSectionFragment(); return mediaFragment; } case FILES_PAGE: { filesFragment = new FilesSectionFragment(); return filesFragment; } } } @Override public int getCount() { return PAGE_COUNT; } @Override public CharSequence getPageTitle(int position) { Locale l = Locale.getDefault(); switch (position) { case CHANNELS_PAGE: return getString(R.string.title_section_channels).toUpperCase(l); case CHAT_PAGE: return getString(R.string.title_section_chat).toUpperCase(l); case MEDIA_PAGE: return getString(R.string.title_section_media).toUpperCase(l); case FILES_PAGE: return getString(R.string.title_section_files).toUpperCase(l); } return null; } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); View v = getCurrentFocus(); if (v != null) imm.hideSoftInputFromWindow(v.getWindowToken(), 0); accessibilityAssistant.setVisiblePage(position); } @Override public void onPageScrollStateChanged(int state) { } } private void editChannelProperties(Channel channel) { Intent intent = new Intent(this, ChannelPropActivity.class); startActivityForResult(intent.putExtra(ChannelPropActivity.EXTRA_CHANNELID, channel.nChannelID), REQUEST_EDITCHANNEL); } private void joinChannelUnsafe(Channel channel, String passwd) { int cmdid = ttclient.doJoinChannelByID(channel.nChannelID, passwd); if (cmdid > 0) { activecmds.put(cmdid, CmdComplete.CMD_COMPLETE_JOIN); channel.szPassword = passwd; ttservice.setJoinChannel(channel); } else { Toast.makeText(this, R.string.text_con_cmderr, Toast.LENGTH_LONG).show(); } } private void joinChannel(final Channel channel, final String passwd) { if (filesAdapter.getActiveTransfersCount() > 0) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setMessage(R.string.channel_change_alert); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { filesAdapter.cancelAllTransfers(); joinChannelUnsafe(channel, passwd); } }); alert.setNegativeButton(android.R.string.cancel, null); alert.show(); } else { joinChannelUnsafe(channel, passwd); } } private void joinChannel(final Channel channel) { if (channel.bPassword) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle(R.string.pref_title_join_channel); alert.setMessage(R.string.channel_password_prompt); final EditText input = new EditText(this); input.setTransformationMethod(SingleLineTransformationMethod.getInstance()); input.setText(channel.szPassword); alert.setView(input); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { joinChannel(channel, input.getText().toString()); } }); alert.setNegativeButton(android.R.string.cancel, null); alert.show(); } else { joinChannel(channel, ""); } } private void setCurrentChannel(Channel channel) { curchannel = channel; getActionBar().setSubtitle((channel != null) ? channel.szName : null); invalidateOptionsMenu(); } private boolean isVisibleChannel(int chanid) { if (curchannel != null) { if (curchannel.nParentID == chanid) return true; Channel channel = ttservice.getChannels().get(chanid); if (channel != null) return curchannel.nChannelID == channel.nParentID; } else { return chanid == ttclient.getRootChannelID(); } return false; } public static class ChannelsSectionFragment extends Fragment { MainActivity mainActivity; public ChannelsSectionFragment() { } @Override public void onAttach(Activity activity) { mainActivity = (MainActivity) activity; super.onAttach(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main_channels, container, false); mainActivity.accessibilityAssistant.registerPage(rootView, SectionsPagerAdapter.CHANNELS_PAGE); ListView channelsList = (ListView) rootView.findViewById(R.id.listChannels); channelsList.setAdapter(mainActivity.getChannelsAdapter()); channelsList.setOnItemClickListener(mainActivity); channelsList.setOnItemLongClickListener(mainActivity); return rootView; } } public static class ChatSectionFragment extends Fragment { MainActivity mainActivity; public ChatSectionFragment() { } @Override public void onAttach(Activity activity) { mainActivity = (MainActivity) activity; super.onAttach(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main_chat, container, false); mainActivity.accessibilityAssistant.registerPage(rootView, SectionsPagerAdapter.CHAT_PAGE); final EditText newmsg = (EditText) rootView.findViewById(R.id.channel_im_edittext); ListView chatlog = (ListView) rootView.findViewById(R.id.channel_im_listview); chatlog.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); chatlog.setAdapter(mainActivity.getTextMessagesAdapter()); Button sendBtn = (Button) rootView.findViewById(R.id.channel_im_sendbtn); sendBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { TextMessage textmsg = new TextMessage(); textmsg.nMsgType = TextMsgType.MSGTYPE_CHANNEL; textmsg.nChannelID = mainActivity.ttclient.getMyChannelID(); textmsg.szMessage = newmsg.getText().toString(); int cmdid = mainActivity.ttclient.doTextMessage(textmsg); if (cmdid > 0) { mainActivity.activecmds.put(cmdid, CmdComplete.CMD_COMPLETE_TEXTMSG); newmsg.setText(""); } else { Toast.makeText(mainActivity, getResources().getString(R.string.text_con_cmderr), Toast.LENGTH_LONG).show(); } } }); return rootView; } } public static class VidcapSectionFragment extends Fragment { MainActivity mainActivity; public VidcapSectionFragment() { } @Override public void onAttach(Activity activity) { mainActivity = (MainActivity) activity; super.onAttach(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main_vidcap, container, false); // mainActivity.accessibilityAssistant.registerPage(rootView, SectionsPagerAdapter.VIDCAP_PAGE); return rootView; } } public static class MediaSectionFragment extends Fragment { MainActivity mainActivity; public MediaSectionFragment() { } @Override public void onAttach(Activity activity) { mainActivity = (MainActivity) activity; super.onAttach(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main_media, container, false); mainActivity.accessibilityAssistant.registerPage(rootView, SectionsPagerAdapter.MEDIA_PAGE); ExpandableListView mediaview = (ExpandableListView) rootView.findViewById(R.id.media_elist_view); mediaview.setAdapter(mainActivity.getMediaAdapter()); return rootView; } } public static class FilesSectionFragment extends ListFragment { @Override public void onViewCreated(View view, Bundle savedInstanceState) { MainActivity mainActivity = (MainActivity) getActivity(); mainActivity.accessibilityAssistant.registerPage(view, SectionsPagerAdapter.FILES_PAGE); setListAdapter(mainActivity.getFilesAdapter()); super.onViewCreated(view, savedInstanceState); } } class ChannelListAdapter extends BaseAdapter { private static final int PARENT_CHANNEL_VIEW_TYPE = 0, CHANNEL_VIEW_TYPE = 1, USER_VIEW_TYPE = 2, VIEW_TYPE_COUNT = 3; private LayoutInflater inflater; Vector<Channel> subchannels = new Vector<Channel>(); Vector<User> currentusers = new Vector<User>(); ChannelListAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public void notifyDataSetChanged() { int chanid = 0; subchannels.clear(); currentusers.clear(); if (curchannel != null) { chanid = curchannel.nChannelID; subchannels = Utils.getSubChannels(chanid, ttservice.getChannels()); currentusers = Utils.getUsers(chanid, ttservice.getUsers()); } else { chanid = ttclient.getRootChannelID(); Channel root = ttservice.getChannels().get(chanid); if (root != null) subchannels.add(root); } Collections.sort(subchannels, new Comparator<Channel>() { @Override public int compare(Channel c1, Channel c2) { return c1.szName.compareToIgnoreCase(c2.szName); } }); Collections.sort(currentusers, new Comparator<User>() { @Override public int compare(User u1, User u2) { if (((u1.uUserState & UserState.USERSTATE_VOICE) != 0) && ((u2.uUserState & UserState.USERSTATE_VOICE) == 0)) return -1; else if (((u1.uUserState & UserState.USERSTATE_VOICE) == 0) && ((u2.uUserState & UserState.USERSTATE_VOICE) != 0)) return 1; String name1 = Utils.getDisplayName(getBaseContext(), u1); String name2 = Utils.getDisplayName(getBaseContext(), u2); return name1.compareToIgnoreCase(name2); } }); super.notifyDataSetChanged(); } @Override public int getCount() { int count = subchannels.size() + currentusers.size(); if ((curchannel != null) && (curchannel.nParentID > 0)) { count++; // include parent channel shortcut } return count; } @Override public Object getItem(int position) { if ((curchannel != null) && (curchannel.nParentID > 0)) { if (position == 0) { Channel parent = ttservice.getChannels().get(curchannel.nParentID); if (parent != null) return parent; return new Channel(); } position--; // substract parent channel shortcut } if (position < subchannels.size()) { return subchannels.get(position); } else { position -= subchannels.size(); return currentusers.get(position); } } @Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { if ((curchannel != null) && (curchannel.nParentID > 0)) { if (position == 0) { return PARENT_CHANNEL_VIEW_TYPE; } else if (position <= subchannels.size()) { return CHANNEL_VIEW_TYPE; } return USER_VIEW_TYPE; } else if (position < subchannels.size()) { return CHANNEL_VIEW_TYPE; } return USER_VIEW_TYPE; } @Override public int getViewTypeCount() { return VIEW_TYPE_COUNT; } @Override public View getView(int position, View convertView, ViewGroup parent) { Object item = getItem(position); if (item instanceof Channel) { final Channel channel = (Channel) item; if ((curchannel != null) && (curchannel.nParentID > 0) && (position == 0)) { // show parent channel shortcut if (convertView == null || convertView.findViewById(R.id.parentname) == null) convertView = inflater.inflate(R.layout.item_channel_back, parent, false); } else { if (convertView == null || convertView.findViewById(R.id.channelname) == null) convertView = inflater.inflate(R.layout.item_channel, parent, false); ImageView chanicon = (ImageView) convertView.findViewById(R.id.channelicon); TextView name = (TextView) convertView.findViewById(R.id.channelname); TextView topic = (TextView) convertView.findViewById(R.id.chantopic); Button join = (Button) convertView.findViewById(R.id.join_btn); int icon_resource = R.drawable.channel_orange; if (channel.bPassword) { icon_resource = R.drawable.channel_pink; chanicon.setContentDescription(getString(R.string.text_passwdprot)); chanicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } else { chanicon.setContentDescription(null); chanicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); } chanicon.setImageResource(icon_resource); if (channel.nParentID == 0) { // show server name as channel name for root channel ServerProperties srvprop = new ServerProperties(); ttclient.getServerProperties(srvprop); name.setText(srvprop.szServerName); } else { name.setText(channel.szName); } topic.setText(channel.szTopic); OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.join_btn: { joinChannel(channel); } break; } } }; join.setOnClickListener(listener); join.setAccessibilityDelegate(accessibilityAssistant); join.setEnabled(channel.nChannelID != ttclient.getMyChannelID()); } int population = Utils.getUsers(channel.nChannelID, ttservice.getUsers()).size(); ((TextView) convertView.findViewById(R.id.population)) .setText((population > 0) ? String.format("(%d)", population) : ""); } else if (item instanceof User) { if (convertView == null || convertView.findViewById(R.id.nickname) == null) convertView = inflater.inflate(R.layout.item_user, parent, false); ImageView usericon = (ImageView) convertView.findViewById(R.id.usericon); TextView nickname = (TextView) convertView.findViewById(R.id.nickname); TextView status = (TextView) convertView.findViewById(R.id.status); final User user = (User) item; String name = Utils.getDisplayName(getBaseContext(), user); nickname.setText(name); status.setText(user.szStatusMsg); boolean talking = (user.uUserState & UserState.USERSTATE_VOICE) != 0; boolean female = (user.nStatusMode & TeamTalkConstants.STATUSMODE_FEMALE) != 0; boolean away = (user.nStatusMode & TeamTalkConstants.STATUSMODE_AWAY) != 0; int icon_resource = R.drawable.man_blue; if (user.nUserID == ttservice.getTTInstance().getMyUserID()) { talking = ttservice.isVoiceTransmitting(); } if (talking) { String name1 = Utils.getDisplayName(getBaseContext(), user); nickname.setContentDescription(getString(R.string.user_state_now_speaking, name1)); if (female) { icon_resource = R.drawable.woman_green; } else { icon_resource = R.drawable.man_green; } } else { nickname.setContentDescription(null); if (female) { icon_resource = away ? R.drawable.woman_orange : R.drawable.woman_blue; } else { icon_resource = away ? R.drawable.man_orange : R.drawable.man_blue; } } usericon.setImageResource(icon_resource); usericon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); Button sndmsg = (Button) convertView.findViewById(R.id.msg_btn); OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.msg_btn: { Intent intent = new Intent(MainActivity.this, TextMessageActivity.class); startActivity(intent.putExtra(TextMessageActivity.EXTRA_USERID, user.nUserID)); break; } } } }; sndmsg.setOnClickListener(listener); sndmsg.setAccessibilityDelegate(accessibilityAssistant); } convertView.setAccessibilityDelegate(accessibilityAssistant); return convertView; } } void createStatusTimer() { final TextView connection = (TextView) findViewById(R.id.connectionstat_textview); final TextView ping = (TextView) findViewById(R.id.pingstat_textview); final TextView total = (TextView) findViewById(R.id.totalstat_textview); final int defcolor = connection.getTextColors().getDefaultColor(); if (stats_timer == null) { stats_timer = new CountDownTimer(10000, 1000) { ClientStatistics prev_stats; public void onTick(long millisUntilFinished) { if (ttclient == null || accessibilityAssistant.isUiUpdateDiscouraged()) return; filesAdapter.performPendingUpdate(); int con = R.string.stat_offline; int con_color = Color.RED; int flags = ttclient.getFlags(); if ((flags & ClientFlag.CLIENT_CONNECTED) == ClientFlag.CLIENT_CONNECTED) { con = R.string.stat_online; con_color = Color.GREEN; } else if ((flags & ClientFlag.CLIENT_CONNECTING) == ClientFlag.CLIENT_CONNECTING) { con = R.string.stat_connecting; } connection.setText(con); connection.setTextColor(con_color); ClientStatistics stats = new ClientStatistics(); if (!ttclient.getClientStatistics(stats)) return; if (prev_stats == null) prev_stats = stats; long totalrx = stats.nUdpBytesRecv - prev_stats.nUdpBytesRecv; long totaltx = stats.nUdpBytesSent - prev_stats.nUdpBytesSent; long voicerx = stats.nVoiceBytesRecv - prev_stats.nVoiceBytesRecv; long voicetx = stats.nVoiceBytesSent - prev_stats.nVoiceBytesSent; long deskrx = stats.nDesktopBytesRecv - prev_stats.nDesktopBytesRecv; long desktx = stats.nDesktopBytesSent - prev_stats.nDesktopBytesSent; long mfrx = (stats.nMediaFileAudioBytesRecv + stats.nMediaFileVideoBytesRecv) - (prev_stats.nMediaFileAudioBytesRecv + prev_stats.nMediaFileVideoBytesRecv); long mftx = (stats.nMediaFileAudioBytesSent + stats.nMediaFileVideoBytesSent) - (prev_stats.nMediaFileAudioBytesSent + prev_stats.nMediaFileVideoBytesSent); String str; if (stats.nUdpPingTimeMs >= 0) { str = String.format("%1$d", stats.nUdpPingTimeMs); ping.setText(str); if (stats.nUdpPingTimeMs > 250) { ping.setTextColor(Color.RED); } else { ping.setTextColor(defcolor); } } str = String.format("%1$d/%2$d KB", totalrx / 1024, totaltx / 1024); total.setText(str); prev_stats = stats; } public void onFinish() { start(); } }.start(); } } @Override public void onItemClick(AdapterView<?> l, View v, int position, long id) { Object item = channelsAdapter.getItem(position); if (item instanceof User) { User user = (User) item; Intent intent = new Intent(this, UserPropActivity.class); // TODO: check 'curchannel' for null startActivityForResult(intent.putExtra(UserPropActivity.EXTRA_USERID, user.nUserID), REQUEST_EDITUSER); } else if (item instanceof Channel) { Channel channel = (Channel) item; setCurrentChannel((channel.nChannelID > 0) ? channel : null); channelsAdapter.notifyDataSetChanged(); } else { } } Channel selectedChannel; User selectedUser; List<Integer> userIDS = new ArrayList<Integer>(); @Override public boolean onItemLongClick(AdapterView<?> l, View v, int position, long id) { Object item = channelsAdapter.getItem(position); if (item instanceof User) { selectedUser = (User) item; UserAccount myuseraccount = new UserAccount(); ttclient.getMyUserAccount(myuseraccount); boolean banRight = (myuseraccount.uUserRights & UserRight.USERRIGHT_BAN_USERS) != 0; boolean moveRight = (myuseraccount.uUserRights & UserRight.USERRIGHT_MOVE_USERS) != 0; boolean kickRight = (myuseraccount.uUserRights & UserRight.USERRIGHT_KICK_USERS) != 0; // operator of a channel can also kick users int myuserid = ttclient.getMyUserID(); kickRight |= ttclient.isChannelOperator(myuserid, selectedUser.nChannelID); PopupMenu userActions = new PopupMenu(this, v); userActions.setOnMenuItemClickListener(this); userActions.inflate(R.menu.user_actions); userActions.getMenu().findItem(R.id.action_kickchan).setEnabled(kickRight).setVisible(kickRight); userActions.getMenu().findItem(R.id.action_kicksrv).setEnabled(kickRight).setVisible(kickRight); userActions.getMenu().findItem(R.id.action_banchan).setEnabled(banRight).setVisible(banRight); userActions.getMenu().findItem(R.id.action_bansrv).setEnabled(banRight).setVisible(banRight); userActions.getMenu().findItem(R.id.action_select).setEnabled(moveRight).setVisible(moveRight); userActions.show(); return true; } if (item instanceof Channel) { selectedChannel = (Channel) item; if ((curchannel != null) && (curchannel.nParentID != selectedChannel.nChannelID)) { boolean isRemovable = (ttclient != null) && (selectedChannel.nChannelID != ttclient.getMyChannelID()); PopupMenu channelActions = new PopupMenu(this, v); channelActions.setOnMenuItemClickListener(this); channelActions.inflate(R.menu.channel_actions); channelActions.getMenu().findItem(R.id.action_remove).setEnabled(isRemovable) .setVisible(isRemovable); channelActions.show(); return true; } } return false; } @Override public boolean onMenuItemClick(MenuItem item) { AlertDialog.Builder alert = new AlertDialog.Builder(this); switch (item.getItemId()) { case R.id.action_banchan: alert.setMessage(getString(R.string.ban_confirmation, selectedUser.szNickname)); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { ttclient.doBanUser(selectedUser.nUserID, selectedUser.nChannelID); ttclient.doKickUser(selectedUser.nUserID, selectedUser.nChannelID); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); break; case R.id.action_bansrv: alert.setMessage(getString(R.string.ban_confirmation, selectedUser.szNickname)); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { ttclient.doBanUser(selectedUser.nUserID, 0); ttclient.doKickUser(selectedUser.nUserID, 0); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); break; case R.id.action_edit: editChannelProperties(selectedChannel); break; case R.id.action_kickchan: alert.setMessage(getString(R.string.kick_confirmation, selectedUser.szNickname)); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { ttclient.doKickUser(selectedUser.nUserID, selectedUser.nChannelID); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); break; case R.id.action_kicksrv: alert.setMessage(getString(R.string.kick_confirmation, selectedUser.szNickname)); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { ttclient.doKickUser(selectedUser.nUserID, 0); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); break; case R.id.action_move: Iterator<Integer> userIDSIterator = userIDS.iterator(); while (userIDSIterator.hasNext()) { ttclient.doMoveUser(userIDSIterator.next(), selectedChannel.nChannelID); } userIDS.clear(); break; case R.id.action_select: userIDS.add(selectedUser.nUserID); break; case R.id.action_remove: { alert.setMessage(getString(R.string.channel_remove_confirmation, selectedChannel.szName)); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { if (ttclient.doRemoveChannel(selectedChannel.nChannelID) <= 0) Toast.makeText(MainActivity.this, getString(R.string.err_channel_remove, selectedChannel.szName), Toast.LENGTH_LONG) .show(); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); break; } default: return false; } return true; } private void adjustMuteButton(ImageButton btn) { if (ttservice.getCurrentMuteState()) { btn.setImageResource(R.drawable.mute_blue); btn.setContentDescription(getString(R.string.speaker_unmute)); } else { btn.setImageResource(R.drawable.speaker_blue); btn.setContentDescription(getString(R.string.speaker_mute)); } } private void adjustVoxState(boolean voiceActivationEnabled, int level) { ImageButton voxSwitch = (ImageButton) findViewById(R.id.voxSwitch); TextView mikeLevel = (TextView) findViewById(R.id.mikelevel_text); if (voiceActivationEnabled) { mikeLevel.setText(level + "%"); mikeLevel.setContentDescription(getString(R.string.vox_level_description, mikeLevel.getText())); voxSwitch.setImageResource(R.drawable.microphone); voxSwitch.setContentDescription(getString(R.string.voice_activation_off)); findViewById(R.id.mikeDec).setContentDescription(getString(R.string.decvoxlevel)); findViewById(R.id.mikeInc).setContentDescription(getString(R.string.incvoxlevel)); } else { mikeLevel.setText(Utils.refVolumeToPercent(level) + "%"); mikeLevel.setContentDescription(getString(R.string.mic_gain_description, mikeLevel.getText())); voxSwitch.setImageResource(R.drawable.mike_green); voxSwitch.setContentDescription(getString(R.string.voice_activation_on)); findViewById(R.id.mikeDec).setContentDescription(getString(R.string.decgain)); findViewById(R.id.mikeInc).setContentDescription(getString(R.string.incgain)); } } private void adjustTxState(boolean txEnabled) { findViewById(R.id.transmit_voice).setBackgroundColor(txEnabled ? Color.GREEN : Color.RED); findViewById(R.id.transmit_voice) .setContentDescription(txEnabled ? getString(R.string.tx_on) : getString(R.string.tx_off)); if ((curchannel != null) && (ttclient.getMyChannelID() == curchannel.nChannelID)) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } private void setupButtons() { final Button tx_btn = (Button) findViewById(R.id.transmit_voice); tx_btn.setOnTouchListener(new OnTouchListener() { boolean tx_state = false; long tx_down_start = 0; @Override public boolean onTouch(View v, MotionEvent event) { boolean tx = event.getAction() != MotionEvent.ACTION_UP; if (tx != tx_state) { if (!tx) { if (System.currentTimeMillis() - tx_down_start < 800) { tx = true; tx_down_start = 0; } else { tx_down_start = System.currentTimeMillis(); } //Log.i(TAG, "TX is now: " + tx + " diff " + (System.currentTimeMillis() - tx_down_start)); } if (ttservice.isVoiceActivationEnabled()) ttservice.enableVoiceActivation(false); ttservice.enableVoiceTransmission(tx); } tx_state = tx; return true; } }); final ImageButton decVol = (ImageButton) findViewById(R.id.volDec); final ImageButton incVol = (ImageButton) findViewById(R.id.volInc); final ImageButton decMike = (ImageButton) findViewById(R.id.mikeDec); final ImageButton incMike = (ImageButton) findViewById(R.id.mikeInc); final TextView mikeLevel = (TextView) findViewById(R.id.mikelevel_text); final TextView volLevel = (TextView) findViewById(R.id.vollevel_text); OnTouchListener listener = new OnTouchListener() { Handler handler = new Handler(); Runnable runnable; @Override public boolean onTouch(final View v, MotionEvent event) { if (ttclient == null) return false; if (event.getAction() == MotionEvent.ACTION_DOWN) { adjustLevel(v); runnable = new Runnable() { @Override public void run() { boolean done = adjustLevel(v); if (!done) handler.postDelayed(this, 100); } }; handler.postDelayed(runnable, 100); } else if (event.getAction() == MotionEvent.ACTION_UP) { if (runnable != null) handler.removeCallbacks(runnable); } return false; } boolean adjustLevel(View view) { if (view == decVol) { // pressing +/- aborts mute state if (ttservice.isMute()) { ttservice.setMute(false); ImageButton speakerBtn = (ImageButton) findViewById(R.id.speakerBtn); adjustMuteButton(speakerBtn); } int v = ttclient.getSoundOutputVolume(); v = Utils.refVolumeToPercent(v); v = Utils.refVolume(v - 1); if (v >= SoundLevel.SOUND_VOLUME_MIN) { ttclient.setSoundOutputVolume(v); volLevel.setText(Utils.refVolumeToPercent(v) + "%"); volLevel.setContentDescription( getString(R.string.speaker_volume_description, volLevel.getText())); if (v == SoundLevel.SOUND_VOLUME_DEFAULT) return true; } else return true; } else if (view == incVol) { // pressing +/- aborts mute state if (ttservice.isMute()) { ttservice.setMute(false); ImageButton speakerBtn = (ImageButton) findViewById(R.id.speakerBtn); adjustMuteButton(speakerBtn); } int v = ttclient.getSoundOutputVolume(); v = Utils.refVolumeToPercent(v); v = Utils.refVolume(v + 1); if (v <= SoundLevel.SOUND_VOLUME_MAX) { ttclient.setSoundOutputVolume(v); volLevel.setText(Utils.refVolumeToPercent(v) + "%"); volLevel.setContentDescription( getString(R.string.speaker_volume_description, volLevel.getText())); if (v == SoundLevel.SOUND_VOLUME_DEFAULT) return true; } else return true; } else if (view == decMike) { if (ttservice.isVoiceActivationEnabled()) { int x = ttclient.getVoiceActivationLevel() - 1; if (x >= SoundLevel.SOUND_VU_MIN) { ttclient.setVoiceActivationLevel(x); mikeLevel.setText(x + "%"); mikeLevel.setContentDescription( getString(R.string.vox_level_description, mikeLevel.getText())); } else return true; } else { int g = ttclient.getSoundInputGainLevel(); g = Utils.refGainToPercent(g); g = Utils.refGain(g - 1); if (g >= SoundLevel.SOUND_GAIN_MIN) { ttclient.setSoundInputGainLevel(g); mikeLevel.setText(Utils.refVolumeToPercent(g) + "%"); mikeLevel.setContentDescription( getString(R.string.mic_gain_description, mikeLevel.getText())); if (g == SoundLevel.SOUND_GAIN_DEFAULT) return true; } else return true; } } else if (view == incMike) { if (ttservice.isVoiceActivationEnabled()) { int x = ttclient.getVoiceActivationLevel() + 1; if (x <= SoundLevel.SOUND_VU_MAX) { ttclient.setVoiceActivationLevel(x); mikeLevel.setText(x + "%"); mikeLevel.setContentDescription( getString(R.string.vox_level_description, mikeLevel.getText())); } else return true; } else { int g = ttclient.getSoundInputGainLevel(); g = Utils.refGainToPercent(g); g = Utils.refGain(g + 1); if (g <= SoundLevel.SOUND_GAIN_MAX) { ttclient.setSoundInputGainLevel(g); mikeLevel.setText(Utils.refVolumeToPercent(g) + "%"); mikeLevel.setContentDescription( getString(R.string.mic_gain_description, mikeLevel.getText())); if (g == SoundLevel.SOUND_VOLUME_DEFAULT) return true; } else return true; } } return false; } }; decVol.setOnTouchListener(listener); incVol.setOnTouchListener(listener); decMike.setOnTouchListener(listener); incMike.setOnTouchListener(listener); ImageButton speakerBtn = (ImageButton) findViewById(R.id.speakerBtn); speakerBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if ((mConnection != null) && mConnection.isBound()) { ttservice.setMute(!ttservice.isMute()); adjustMuteButton((ImageButton) v); int level = ttservice.isMute() ? 0 : Utils.refVolumeToPercent(ttclient.getSoundOutputVolume()); volLevel.setText(level + "%"); volLevel.setContentDescription( getString(R.string.speaker_volume_description, volLevel.getText())); } } }); ImageButton voxSwitch = (ImageButton) findViewById(R.id.voxSwitch); voxSwitch.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if ((mConnection != null) && mConnection.isBound()) { if (ttservice.isVoiceTransmissionEnabled()) ttservice.enableVoiceTransmission(false); ttservice.enableVoiceActivation(!ttservice.isVoiceActivationEnabled()); } } }); } @Override public void onServiceConnected(TeamTalkService service) { ttservice = service; ttclient = ttservice.getTTInstance(); //ttclient.DBG_SetSoundInputTone(StreamType.STREAMTYPE_VOICE, 440); int mychannel = ttclient.getMyChannelID(); if (mychannel > 0) { setCurrentChannel(ttservice.getChannels().get(mychannel)); } this.mychannel = ttservice.getChannels().get(mychannel); mSectionsPagerAdapter.onPageSelected(mViewPager.getCurrentItem()); channelsAdapter.notifyDataSetChanged(); textmsgAdapter.setTextMessages(ttservice.getChatLogTextMsgs()); textmsgAdapter.setMyUserID(ttclient.getMyUserID()); textmsgAdapter.notifyDataSetChanged(); mediaAdapter.setTeamTalkService(service); mediaAdapter.notifyDataSetChanged(); filesAdapter.setTeamTalkService(service); filesAdapter.update(mychannel); int flags = ttclient.getFlags(); if (((flags & ClientFlag.CLIENT_SNDOUTPUT_READY) == 0) && !ttclient.initSoundOutputDevice(0)) Toast.makeText(this, R.string.err_init_sound_output, Toast.LENGTH_LONG).show(); if (!restarting) { ttservice.setMute(false); ttservice.enableVoiceTransmission(false); ttservice.enableVoiceActivation(false); if (Permissions.setupPermission(getBaseContext(), this, Permissions.MY_PERMISSIONS_REQUEST_READ_PHONE_STATE)) ttservice.enablePhoneCallReaction(); } ttservice.registerConnectionListener(this); ttservice.registerCommandListener(this); ttservice.registerUserListener(this); ttservice.registerClientListener(this); ttservice.setOnVoiceTransmissionToggleListener(this); audioManager.registerMediaButtonEventReceiver(mediaButtonEventReceiver); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); if (Permissions.setupPermission(getBaseContext(), this, Permissions.MY_PERMISSIONS_REQUEST_WAKE_LOCK)) wakeLock.acquire(); int mastervol = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_MASTERVOLUME, SoundLevel.SOUND_VOLUME_DEFAULT); int gain = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_MICROPHONEGAIN, SoundLevel.SOUND_GAIN_DEFAULT); int voxlevel = prefs.getInt(Preferences.PREF_SOUNDSYSTEM_VOICEACTIVATION_LEVEL, 5); boolean voxState = ttservice.isVoiceActivationEnabled(); boolean txState = ttservice.isVoiceTransmitting(); // only set volume and gain if tt-instance hasn't already been configured if (ttclient.getSoundOutputVolume() != mastervol) ttclient.setSoundOutputVolume(mastervol); if (ttclient.getSoundInputGainLevel() != gain) ttclient.setSoundInputGainLevel(gain); if (ttclient.getVoiceActivationLevel() != voxlevel) ttclient.setVoiceActivationLevel(voxlevel); adjustMuteButton((ImageButton) findViewById(R.id.speakerBtn)); adjustVoxState(voxState, voxState ? voxlevel : gain); adjustTxState(txState); TextView volLevel = (TextView) findViewById(R.id.vollevel_text); volLevel.setText(Utils.refVolumeToPercent(mastervol) + "%"); volLevel.setContentDescription(getString(R.string.speaker_volume_description, volLevel.getText())); } @Override public void onServiceDisconnected(TeamTalkService service) { if (wakeLock.isHeld()) wakeLock.release(); audioManager.unregisterMediaButtonEventReceiver(mediaButtonEventReceiver); service.setOnVoiceTransmissionToggleListener(null); service.unregisterConnectionListener(this); service.unregisterCommandListener(this); service.unregisterUserListener(this); service.unregisterClientListener(this); filesAdapter.setTeamTalkService(null); mediaAdapter.clearTeamTalkService(service); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; switch (requestCode) { case Permissions.MY_PERMISSIONS_REQUEST_VIBRATE: break; case Permissions.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: startActivityForResult(new Intent(this, FilePickerActivity.class), REQUEST_SELECT_FILE); break; case Permissions.MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: break; case Permissions.MY_PERMISSIONS_REQUEST_WAKE_LOCK: wakeLock.acquire(); break; case Permissions.MY_PERMISSIONS_REQUEST_READ_PHONE_STATE: if ((mConnection != null) && mConnection.isBound()) ttservice.enablePhoneCallReaction(); break; } } @Override public void onCmdError(int cmdId, ClientErrorMsg errmsg) { // error is notified in service } @Override public void onCmdSuccess(int cmdId) { } @Override public void onCmdProcessing(int cmdId, boolean complete) { if (complete) { activecmds.remove(cmdId); } } @Override public void onCmdMyselfLoggedIn(int my_userid, UserAccount useraccount) { textmsgAdapter.setMyUserID(my_userid); } @Override public void onCmdMyselfLoggedOut() { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } @Override public void onCmdMyselfKickedFromChannel() { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } @Override public void onCmdMyselfKickedFromChannel(User kicker) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } @Override public void onCmdUserLoggedIn(User user) { if (ttsWrapper != null && PreferenceManager.getDefaultSharedPreferences(getBaseContext()) .getBoolean("server_login_checkbox", false)) { String name = Utils.getDisplayName(getBaseContext(), user); ttsWrapper.speak(name + " " + getResources().getString(R.string.text_tts_loggedin)); } } @Override public void onCmdUserLoggedOut(User user) { if (ttsWrapper != null && PreferenceManager.getDefaultSharedPreferences(getBaseContext()) .getBoolean("server_logout_checkbox", false)) { String name = Utils.getDisplayName(getBaseContext(), user); ttsWrapper.speak(name + " " + getResources().getString(R.string.text_tts_loggedout)); } } @Override public void onCmdUserUpdate(User user) { if (curchannel != null && curchannel.nChannelID == user.nChannelID) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onCmdUserJoinedChannel(User user) { if (user.nUserID == ttclient.getMyUserID()) { //myself joined channel Channel chan = ttservice.getChannels().get(user.nChannelID); setCurrentChannel(chan); filesAdapter.update(curchannel); //store copy of channel mychannel = chan; //update the displayed channel to the one we're currently in accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } else if (curchannel != null && curchannel.nChannelID == user.nChannelID) { //other user joined current channel } if (curchannel != null && curchannel.nChannelID == user.nChannelID) { //event took place in current channel if (user.nUserID != ttclient.getMyUserID()) { accessibilityAssistant.lockEvents(); textmsgAdapter.notifyDataSetChanged(); channelsAdapter.notifyDataSetChanged(); if (ttclient.getMyChannelID() == user.nChannelID) { if (sounds.get(SOUND_USERJOIN) != 0) audioIcons.play(sounds.get(SOUND_USERJOIN), 1.0f, 1.0f, 0, 0, 1.0f); if (ttsWrapper != null && PreferenceManager.getDefaultSharedPreferences(getBaseContext()) .getBoolean("channel_join_checkbox", false)) { String name = Utils.getDisplayName(getBaseContext(), user); ttsWrapper.speak(name + " " + getResources().getString(R.string.text_tts_joined_chan)); } } accessibilityAssistant.unlockEvents(); } else { textmsgAdapter.notifyDataSetChanged(); channelsAdapter.notifyDataSetChanged(); } } else if (isVisibleChannel(user.nChannelID)) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onCmdUserLeftChannel(int channelid, User user) { if (user.nUserID == ttclient.getMyUserID()) { //myself left current channel Channel chan = ttservice.getChannels().get(channelid); textmsgAdapter.notifyDataSetChanged(); setCurrentChannel(null); mychannel = null; } else if (curchannel != null && channelid == curchannel.nChannelID) { //other user left current channel accessibilityAssistant.lockEvents(); textmsgAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } if (curchannel != null && curchannel.nChannelID == channelid) { //event took place in current channel accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); if (ttclient.getMyChannelID() == channelid) { if (sounds.get(SOUND_USERLEFT) != 0) audioIcons.play(sounds.get(SOUND_USERLEFT), 1.0f, 1.0f, 0, 0, 1.0f); if (ttsWrapper != null && PreferenceManager.getDefaultSharedPreferences(getBaseContext()) .getBoolean("channel_leave_checkbox", false)) { String name = Utils.getDisplayName(getBaseContext(), user); ttsWrapper.speak(name + " " + getResources().getString(R.string.text_tts_left_chan)); } } accessibilityAssistant.unlockEvents(); } else if (isVisibleChannel(channelid)) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onCmdUserTextMessage(TextMessage textmessage) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); switch (textmessage.nMsgType) { case TextMsgType.MSGTYPE_CHANNEL: case TextMsgType.MSGTYPE_BROADCAST: accessibilityAssistant.lockEvents(); textmsgAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); // audio event if (sounds.get(SOUND_CHANMSG) != 0) audioIcons.play(sounds.get(SOUND_CHANMSG), 1.0f, 1.0f, 0, 0, 1.0f); // TTS event if (ttsWrapper != null && prefs.getBoolean("broadcast_message_checkbox", false)) { User sender = ttservice.getUsers().get(textmessage.nFromUserID); String name = Utils.getDisplayName(getBaseContext(), sender); ttsWrapper.speak(getString(R.string.text_tts_broadcast_message, (sender != null) ? name : "")); } Log.d(TAG, "Channel message in " + this.hashCode()); break; case TextMsgType.MSGTYPE_USER: if (sounds.get(SOUND_USERMSG) != 0) audioIcons.play(sounds.get(SOUND_USERMSG), 1.0f, 1.0f, 0, 0, 1.0f); User sender = ttservice.getUsers().get(textmessage.nFromUserID); String name = Utils.getDisplayName(getBaseContext(), sender); String senderName = (sender != null) ? name : ""; if (ttsWrapper != null && prefs.getBoolean("personal_message_checkbox", false)) ttsWrapper.speak(getString(R.string.text_tts_personal_message, senderName)); Intent action = new Intent(this, TextMessageActivity.class); Notification.Builder notification = new Notification.Builder(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel mChannel = new NotificationChannel("TT_PM", "Teamtalk incoming message", NotificationManager.IMPORTANCE_HIGH); mChannel.enableVibration(false); mChannel.setVibrationPattern(null); mChannel.enableLights(false); mChannel.setSound(null, null); notificationManager.createNotificationChannel(mChannel); } notification.setSmallIcon(R.drawable.message) .setContentTitle(getString(R.string.personal_message_notification, senderName)) .setContentText(getString(R.string.personal_message_notification_hint)) .setContentIntent(PendingIntent.getActivity(this, textmessage.nFromUserID, action.putExtra(TextMessageActivity.EXTRA_USERID, textmessage.nFromUserID), 0)) .setAutoCancel(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { notification.setChannelId("TT_PM"); } notificationManager.notify(MESSAGE_NOTIFICATION_TAG, textmessage.nFromUserID, notification.build()); break; case TextMsgType.MSGTYPE_CUSTOM: default: break; } } @Override public void onCmdChannelNew(Channel channel) { if (curchannel != null && curchannel.nChannelID == channel.nParentID) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onCmdChannelUpdate(Channel channel) { if (curchannel != null && curchannel.nChannelID == channel.nParentID) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } if (mychannel != null && mychannel.nChannelID == channel.nChannelID) { int myuserid = ttclient.getMyUserID(); if (channel.transmitUsersQueue[0] == myuserid && mychannel.transmitUsersQueue[0] != myuserid) { if (sounds.get(SOUND_TXREADY) != 0) { audioIcons.play(sounds.get(SOUND_TXREADY), 1.0f, 1.0f, 0, 0, 1.0f); } } if (mychannel.transmitUsersQueue[0] == myuserid && channel.transmitUsersQueue[0] != myuserid) { if (sounds.get(SOUND_TXSTOP) != 0) { audioIcons.play(sounds.get(SOUND_TXSTOP), 1.0f, 1.0f, 0, 0, 1.0f); } } mychannel = channel; } } @Override public void onCmdChannelRemove(Channel channel) { if (curchannel != null && curchannel.nChannelID == channel.nParentID) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onCmdServerUpdate(ServerProperties serverproperties) { } @Override public void onCmdFileNew(RemoteFile remotefile) { filesAdapter.update(); if (activecmds.size() == 0) { if (sounds.get(SOUND_FILESUPDATE) != 0) { audioIcons.play(sounds.get(SOUND_FILESUPDATE), 1.0f, 1.0f, 0, 0, 1.0f); } } } @Override public void onCmdFileRemove(RemoteFile remotefile) { filesAdapter.update(); if (activecmds.size() == 0) { if (sounds.get(SOUND_FILESUPDATE) != 0) { audioIcons.play(sounds.get(SOUND_FILESUPDATE), 1.0f, 1.0f, 0, 0, 1.0f); } } } @Override public void onCmdUserAccount(UserAccount useraccount) { } @Override public void onCmdBannedUser(BannedUser banneduser) { } @Override public void onConnectSuccess() { } @Override public void onConnectFailed() { } @Override public void onConnectionLost() { if (sounds.get(SOUND_SERVERLOST) != 0) { audioIcons.play(sounds.get(SOUND_SERVERLOST), 1.0f, 1.0f, 0, 0, 1.0f); } } @Override public void onMaxPayloadUpdate(int payload_size) { } @Override public void onUserStateChange(User user) { if (curchannel != null && user.nChannelID == curchannel.nChannelID) { accessibilityAssistant.lockEvents(); channelsAdapter.notifyDataSetChanged(); accessibilityAssistant.unlockEvents(); } } @Override public void onUserVideoCapture(int nUserID, int nStreamID) { } @Override public void onUserMediaFileVideo(int nUserID, int nStreamID) { } @Override public void onUserDesktopWindow(int nUserID, int nStreamID) { } @Override public void onUserDesktopCursor(int nUserID, DesktopInput desktopinput) { } @Override public void onUserRecordMediaFile(int nUserID, MediaFileInfo mediafileinfo) { } @Override public void onUserAudioBlock(int nUserID, int nStreamType) { } @Override public void onVoiceTransmissionToggle(boolean voiceTransmissionEnabled, boolean isSuspended) { adjustTxState(voiceTransmissionEnabled); if (!isSuspended) { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); boolean ptt_vibrate = pref.getBoolean("vibrate_checkbox", true) && Permissions .setupPermission(getBaseContext(), this, Permissions.MY_PERMISSIONS_REQUEST_VIBRATE); if (voiceTransmissionEnabled) { if (sounds.get(SOUND_VOICETXON) != 0) { audioIcons.play(sounds.get(SOUND_VOICETXON), 1.0f, 1.0f, 0, 0, 1.0f); } if (ptt_vibrate) { Vibrator vibrat = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); vibrat.vibrate(50); } } else { if (sounds.get(SOUND_VOICETXOFF) != 0) { audioIcons.play(sounds.get(SOUND_VOICETXOFF), 1.0f, 1.0f, 0, 0, 1.0f); } if (ptt_vibrate) { Vibrator vibrat = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); long pattern[] = { 0, 20, 80, 20 }; vibrat.vibrate(pattern, -1); } } } } @Override public void onVoiceActivationToggle(boolean voiceActivationEnabled, boolean isSuspended) { adjustVoxState(voiceActivationEnabled, voiceActivationEnabled ? ttclient.getVoiceActivationLevel() : ttclient.getSoundInputGainLevel()); } @Override public void onInternalError(ClientErrorMsg clienterrormsg) { } @Override public void onVoiceActivation(boolean bVoiceActive) { adjustTxState(bVoiceActive); int sound = sounds.get(bVoiceActive ? SOUND_VOXON : SOUND_VOXOFF); if (sound != 0) audioIcons.play(sound, 1.0f, 1.0f, 0, 0, 1.0f); } @Override public void onHotKeyToggle(int nHotKeyID, boolean bActive) { } @Override public void onHotKeyTest(int nVkCode, boolean bActive) { } @Override public void onFileTransfer(FileTransfer filetransfer) { } @Override public void onDesktopWindowTransfer(int nSessionID, int nTransferRemaining) { } @Override public void onStreamMediaFile(MediaFileInfo mediafileinfo) { } }