/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of linphone-android * (see https://www.linphone.org). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.linphone.call; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.core.app.ActivityCompat; import java.util.ArrayList; import org.linphone.LinphoneContext; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.activities.LinphoneGenericActivity; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.contacts.views.ContactAvatar; import org.linphone.core.Address; import org.linphone.core.Call; import org.linphone.core.Call.State; import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; import org.linphone.core.Reason; import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; import org.linphone.utils.LinphoneUtils; public class CallOutgoingActivity extends LinphoneGenericActivity implements OnClickListener { private TextView mName, mNumber; private ImageView mMicro; private ImageView mSpeaker; private Call mCall; private CoreListenerStub mListener; private boolean mIsMicMuted, mIsSpeakerEnabled; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.call_outgoing); mName = findViewById(R.id.contact_name); mNumber = findViewById(R.id.contact_number); mIsMicMuted = false; mIsSpeakerEnabled = false; mMicro = findViewById(R.id.micro); mMicro.setOnClickListener(this); mSpeaker = findViewById(R.id.speaker); mSpeaker.setOnClickListener(this); ImageView hangUp = findViewById(R.id.outgoing_hang_up); hangUp.setOnClickListener(this); mListener = new CoreListenerStub() { @Override public void onCallStateChanged( Core core, Call call, Call.State state, String message) { if (state == State.Error) { // Convert Core message for internalization if (call.getErrorInfo().getReason() == Reason.Declined) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_call_declined), Toast.LENGTH_SHORT) .show(); } else if (call.getErrorInfo().getReason() == Reason.NotFound) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_user_not_found), Toast.LENGTH_SHORT) .show(); } else if (call.getErrorInfo().getReason() == Reason.NotAcceptable) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_incompatible_media), Toast.LENGTH_SHORT) .show(); } else if (call.getErrorInfo().getReason() == Reason.Busy) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_user_busy), Toast.LENGTH_SHORT) .show(); } else if (message != null) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_SHORT) .show(); } } else if (state == State.End) { // Convert Core message for internalization if (call.getErrorInfo().getReason() == Reason.Declined) { Toast.makeText( CallOutgoingActivity.this, getString(R.string.error_call_declined), Toast.LENGTH_SHORT) .show(); } } else if (state == State.Connected) { // This is done by the LinphoneContext listener now // startActivity(new Intent(CallOutgoingActivity.this, // CallActivity.class)); } if (state == State.End || state == State.Released) { finish(); } } }; } @Override protected void onStart() { super.onStart(); checkAndRequestCallPermissions(); } @Override protected void onResume() { super.onResume(); Core core = LinphoneManager.getCore(); if (core != null) { core.addListener(mListener); } mCall = null; // Only one call ringing at a time is allowed if (LinphoneManager.getCore() != null) { for (Call call : LinphoneManager.getCore().getCalls()) { State cstate = call.getState(); if (State.OutgoingInit == cstate || State.OutgoingProgress == cstate || State.OutgoingRinging == cstate || State.OutgoingEarlyMedia == cstate) { mCall = call; break; } } } if (mCall == null) { Log.e("[Call Outgoing Activity] Couldn't find outgoing call"); finish(); return; } Address address = mCall.getRemoteAddress(); LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address); if (contact != null) { ContactAvatar.displayAvatar(contact, findViewById(R.id.avatar_layout), true); mName.setText(contact.getFullName()); } else { String displayName = LinphoneUtils.getAddressDisplayName(address); ContactAvatar.displayAvatar(displayName, findViewById(R.id.avatar_layout), true); mName.setText(displayName); } mNumber.setText(LinphoneUtils.getDisplayableAddress(address)); boolean recordAudioPermissionGranted = checkPermission(Manifest.permission.RECORD_AUDIO); if (!recordAudioPermissionGranted) { Log.w("[Call Outgoing Activity] RECORD_AUDIO permission denied, muting microphone"); core.enableMic(false); mMicro.setSelected(true); } } @Override protected void onPause() { Core core = LinphoneManager.getCore(); if (core != null) { core.removeListener(mListener); } super.onPause(); } @Override protected void onDestroy() { mName = null; mNumber = null; mMicro = null; mSpeaker = null; mCall = null; mListener = null; super.onDestroy(); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.micro) { mIsMicMuted = !mIsMicMuted; mMicro.setSelected(mIsMicMuted); LinphoneManager.getCore().enableMic(!mIsMicMuted); } if (id == R.id.speaker) { mIsSpeakerEnabled = !mIsSpeakerEnabled; mSpeaker.setSelected(mIsSpeakerEnabled); if (mIsSpeakerEnabled) { LinphoneManager.getAudioManager().routeAudioToSpeaker(); } else { LinphoneManager.getAudioManager().routeAudioToEarPiece(); } } if (id == R.id.outgoing_hang_up) { decline(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (LinphoneContext.isReady() && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)) { mCall.terminate(); finish(); } return super.onKeyDown(keyCode, event); } private void decline() { mCall.terminate(); finish(); } private void checkAndRequestCallPermissions() { ArrayList permissionsList = new ArrayList<>(); int recordAudio = getPackageManager() .checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()); Log.i( "[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()); Log.i( "[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); int readPhoneState = getPackageManager() .checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName()); Log.i( "[Permission] Read phone state permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); if (recordAudio != PackageManager.PERMISSION_GRANTED) { Log.i("[Permission] Asking for record audio"); permissionsList.add(Manifest.permission.RECORD_AUDIO); } if (readPhoneState != PackageManager.PERMISSION_GRANTED) { Log.i("[Permission] Asking for read phone state"); permissionsList.add(Manifest.permission.READ_PHONE_STATE); } if (LinphonePreferences.instance().shouldInitiateVideoCall()) { if (camera != PackageManager.PERMISSION_GRANTED) { Log.i("[Permission] Asking for camera"); permissionsList.add(Manifest.permission.CAMERA); } } if (permissionsList.size() > 0) { String[] permissions = new String[permissionsList.size()]; permissions = permissionsList.toArray(permissions); ActivityCompat.requestPermissions(this, permissions, 0); } } private boolean checkPermission(String permission) { int granted = getPackageManager().checkPermission(permission, getPackageName()); Log.i( "[Permission] " + permission + " permission is " + (granted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); return granted == PackageManager.PERMISSION_GRANTED; } @Override public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { for (int i = 0; i < permissions.length; i++) { Log.i( "[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); if (permissions[i].equals(Manifest.permission.CAMERA) && grantResults[i] == PackageManager.PERMISSION_GRANTED) { LinphoneUtils.reloadVideoDevices(); } else if (permissions[i].equals(Manifest.permission.RECORD_AUDIO) && grantResults[i] == PackageManager.PERMISSION_GRANTED) { Core core = LinphoneManager.getCore(); if (core != null) { core.enableMic(true); mMicro.setSelected(!core.micEnabled()); } } } } }