Hello and thanks for your help in advanve,
So I've run into a problem while developing this production code. In some instances the phone seems to be freeze when making outbound calls, this code has been inherited by me to help solve this issue with refactoring and refactor the code. So I'm looking for alternative solutions as well as a fix for this issue.
So my current implementation is using a broadcast receiver to check the state of the phone in the onRecieve() method as shown below
public PhonecallService() {
mApiService = new ApiService();
}
#Override
public void onReceive(Context context, Intent intent) {
Timber.d("ONRECIEVE Service");
String stateStr = intent.getExtras() != null ? intent.getExtras().getString(TelephonyManager.EXTRA_STATE) : "";
String number = intent.getExtras() != null ? intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER) : "";
try {
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
} else {
int state = 0;
if (stateStr != null) {
if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
state = TelephonyManager.CALL_STATE_IDLE;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
state = TelephonyManager.CALL_STATE_OFFHOOK;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
}
}
onCallStateChanged(context, state, number);
}
} catch (Exception e) {
e.printStackTrace();
}
}
This then should call this method and check the state of the phone to then send a broadcast like so:
public void onCallStateChanged(Context context, int state, String number) {
if (lastState == state) {
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if (number != null) {
isIncoming = true;
callStartTime = new Date();
savedNumber = number;
onIncomingCallStarted(context, number, callStartTime);
lastState = state;
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, savedNumber, callStartTime);
} else {
isIncoming = true;
callStartTime = new Date();
onIncomingCallAnswered(context, savedNumber, callStartTime);
}
lastState = state;
break;
case TelephonyManager.CALL_STATE_IDLE:
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
onMissedCall(context, savedNumber, callStartTime);
} else if (isIncoming) {
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
} else {
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
lastState = state;
break;
}
}
This is then handled in the CallOutFragment
public class CallOutFragment extends BaseFragment<MainViewModel, CallOutFragmentBinding> {
private BroadcastReceiver mKeypadBroadCastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
viewModel.getmIncomingCall().postValue(true);
}
};
private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
viewModel.getmIncomingCall().postValue(true);
}
};
#Override
public Class<MainViewModel> getViewModel() {
return MainViewModel.class;
}
#Override
public int getLayoutRes() {
return R.layout.call_out_fragment;
}
public static CallOutFragment newInstance() {
Bundle args = new Bundle();
CallOutFragment fragment = new CallOutFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onDestroy() {
super.onDestroy();
if (getActivity() != null) {
if (mBroadCastReceiver.isOrderedBroadcast()) {
try {
getActivity().unregisterReceiver(mBroadCastReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (mKeypadBroadCastReceiver.isOrderedBroadcast()) {
try {
getActivity().unregisterReceiver(mKeypadBroadCastReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActivity() != null) {
if (mBroadCastReceiver.isOrderedBroadcast()) {
getActivity().registerReceiver(mBroadCastReceiver, new IntentFilter(Constants.PREFERENCES_CALL_OUT_CLOSE_BROADCAST));
}
if (mKeypadBroadCastReceiver.isOrderedBroadcast()) {
getActivity().registerReceiver(mKeypadBroadCastReceiver, new IntentFilter(Constants.KEYPAD_BROADCAST));
}
}
setHasOptionsMenu(false);
}
#Override
public void onPause() {
if (getActivity() != null) {
if (!mBroadCastReceiver.isOrderedBroadcast()) {
try {
getActivity().unregisterReceiver(mBroadCastReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
if (!mKeypadBroadCastReceiver.isOrderedBroadcast()) {
try {
getActivity().unregisterReceiver(mKeypadBroadCastReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
}
getActivity().registerReceiver(mBroadCastReceiver, new IntentFilter(Constants.PREFERENCES_CALL_OUT_CLOSE_BROADCAST));
getActivity().registerReceiver(mKeypadBroadCastReceiver, new IntentFilter(Constants.KEYPAD_BROADCAST));
super.onPause();
}
#Override
public void onResume() {
super.onResume();
if (getActivity() != null) {
getActivity().registerReceiver(mBroadCastReceiver, new IntentFilter(Constants.PREFERENCES_CALL_OUT_CLOSE_BROADCAST));
getActivity().registerReceiver(mKeypadBroadCastReceiver, new IntentFilter(Constants.KEYPAD_BROADCAST));
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(false);
viewModel.getmDialerContactsFilter().postValue(null);
if (getActivity() != null) {
((MainActivity) getActivity()).hideFloatingDialer();
}
viewModel.getmIncomingCall().observe(this, incomingCall -> {
if (incomingCall != null && incomingCall) {
viewModel.getmSelectedNumber().postValue(null);
if (!Fragments.DIALER.equals(FragmentUtils.callOutPreviousFragment)) {
((MainActivity) getActivity()).showFloatingDialer();
}
if (FragmentUtils.currFragment != FragmentUtils.callOutPreviousFragment && FragmentUtils.callOutPreviousFragment != null) {
FragmentUtils.switchFragment((AppCompatActivity) getActivity(), FragmentUtils.callOutPreviousFragment);
}
}
});
String number = viewModel.getmSelectedNumber().getValue();
viewModel.getmOutCallStatus().observe(this, apiCallStatus -> {
if (apiCallStatus != null) {
if (apiCallStatus.getStatus().equals(Status.ERROR)) {
showOkDialog("Outbound call failed please check network", viewModel.getmMode().getValue(),
dialog -> viewModel.getmIncomingCall().postValue(true));
}
}
});
viewModel.getmOutCallDeclineStatus().observe(this, apiCallStatus -> {
if (apiCallStatus != null) {
viewModel.getmIncomingCall().postValue(true);
}
});
if (viewModel.getmConversationId().getValue() == null && viewModel.getmOutCallStatus().getValue() == null) {
if (number != null) {
viewModel.callRemoteNumber(number);
} else {
viewModel.getmIncomingCall().postValue(true);
}
}
Pair<String, String> numberDescription = viewModel.findNumberDescription(number);
if (numberDescription != null) {
dataBinding.outCallName.setText(numberDescription.first);
} else {
if (number != null) {
dataBinding.outCallName.setText(PhonecallService.getNumberSmart(number));
} else {
getString(R.string.number_unknown);
}
}
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
try {
count++;
if (getActivity() != null) {
if (count == 1) {
dataBinding.outTextview.setText(String.format("%s.", getActivity().getResources().getString(R.string.call_out_call)));
} else if (count == 2) {
dataBinding.outTextview.setText(String.format("%s..", getActivity().getResources().getString(R.string.call_out_call)));
} else if (count == 3) {
dataBinding.outTextview.setText(String.format("%s...", getActivity().getResources().getString(R.string.call_out_call)));
}
if (count == 3)
count = 0;
}
handler.postDelayed(this, 2 * 500);
} catch (Exception e) {
Timber.e(e);
}
}
};
handler.postDelayed(runnable, 500);
final Handler closeHandler = new Handler();
Runnable closeRunnable = () -> {
try {
if (Objects.equals(viewModel.getmIncomingCall().getValue(), false)) {
viewModel.getmIncomingCall().postValue(true);
viewModel.timeoutCall();
viewModel.getmDisplayAlert().postValue(getResources().getString(R.string.call_out_fail));
}
} catch (Exception e) {
Timber.e(e);
}
};
closeHandler.postDelayed(closeRunnable, 20000);
dataBinding.getRoot().setFocusableInTouchMode(true);
dataBinding.getRoot().requestFocus();
dataBinding.getRoot().setOnKeyListener((v, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
viewModel.getmIncomingCall().postValue(true);
return true;
}
return false;
});
return dataBinding.getRoot();
}
}
Some of my suspicions have come from how the manifest has been set up so here are the permissions set up in it alongside the receiver settings;
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<receiver
android:name="com.teliqo.pipcall.services.PhonecallService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
<action android:name="android.intent.action.ANSWER" />
<action android:name="android.intent.action.CALL_BUTTON" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
This occurs quite randomly and haven't been able to generate a crash report, the only thing that has I've been able to observe is that the fragment is being called numerous times.
My question is;
1) Is there a reason as to why the phone is frozen when making a call?
2) Is there an alternative, cleaner way to implement this fix?
Thank you very much in advance and I'm open to any suggestions that could help solve this issue
Related
I have developed an Android app for recording audio when the phone called. I know, I can't record the audio of the caller person but I want to record my voice when I answered the phone or start a call with another person. I can do this on some devices but on some devices when my phone starts to ringing, the voice is recorded but after I answered the phone, I can't record any voice. Or my voice is recorded when I start to call to person but after the person answered me, recording voice is stopped!
I use the below code:
private void startRecord(){
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);*/
mRecorder.setOutputFile(savePath);
}
BroadCastReceiver:
private final PhoneStateListener phoneListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
//Toast.makeText(context,"phoneListener Start",Toast.LENGTH_LONG).show();
try {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING: {
startedCall = true;
//Toast.makeText(context,"CALL_STATE_RINGING",Toast.LENGTH_LONG).show();
if (incomingNumber != null) {
//incoming call
//Toast.makeText(context,"Go to start forground service->ringing",Toast.LENGTH_LONG).show();
startForegroundService(incomingNumber);
}
break;
}
case TelephonyManager.CALL_STATE_OFFHOOK: {
//Toast.makeText(context,"CALL_STATE_OFFHOOK",Toast.LENGTH_LONG).show();
startedCall = true; // Newly added code
if (incomingNumber != null) {
//Toast.makeText(context,"Go to start forground service->OffHook",Toast.LENGTH_LONG).show();
//outgoing call
startForegroundService(incomingNumber);
}
break;
}
case TelephonyManager.CALL_STATE_IDLE: {
//Toast.makeText(context,"CALL_STATE_IDLE",Toast.LENGTH_LONG).show();
if (startedCall) {
stopForegroundService();
}
break;
}
default: {
}
}
} catch (Exception ex) {
}
}
};
You have to use the AccessibilityService in Android 10 and above.
MainActivity code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 29) {
if (!isAccessibilityServiceEnabled()) {
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
}
}
}
private boolean isAccessibilityServiceEnabled() {
int accessibilityEnabled = 0;
final String service = getPackageName() + "/" + RecordingAccessibilityService.class.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == 1) {
String settingValue = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
}
return false;
}
AccessibilityService code:
public class RecordingAccessibilityService extends AccessibilityService {
#Override
protected void onServiceConnected() {
instance = this;
super.onServiceConnected();
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
Toast.makeText(getApplicationContext(), "onServiceConnected", Toast.LENGTH_SHORT).show();
updateNotification();
startRecord();
}
if (state == TelephonyManager.CALL_STATE_IDLE) {
stopRecord();
}
super.onCallStateChanged(state, incomingNumber);
}
};
if (mgr != null) {
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
}
Manifest Code:
<service
android:name=".RecordingAccessibilityService"
android:exported="false"
android:label="#string/accessibility_description"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="#xml/accessibility_service_config" />
</service>
accessibility service config code:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowContentChanged|typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
android:canRetrieveWindowContent="true"
android:description="#string/accessibility_description"
android:label="#string/app_name"
android:notificationTimeout="100" />
also must use BroadcastReceiver:
public class CallBroadcastReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
String numberToCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
// Log.d("CallRecorder", "CallBroadcastReceiver intent has EXTRA_PHONE_NUMBER: " + numberToCall);
}
PhoneListener phoneListener = new PhoneListener(context);
TelephonyManager telephony = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
documentation:
https://developer.android.com/reference/android/accessibilityservice/AccessibilityService
I am developing an Android application, where I have asked to implement the call record ,I have gone through SO and found One Solution which is working fine when my app is opened. If I close my app or clear it from recent apps, Call record is not working. Tried searching in the Google and SO but no luck. I am posting my code here, Can some one help me in getting the solution.
CallreCorder Service class:
public class TService extends Service {
MediaRecorder recorder;
File audiofile;
String name, phonenumber;
String audio_format;
public String Audio_Type;
int audioSource;
Context context;
private Handler handler;
Timer timer;
Boolean offHook = false, ringing = false;
Toast toast;
Boolean isOffHook = false;
private boolean recordstarted = false;
private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onDestroy() {
Log.d("service", "destroy");
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// final String terminate =(String)
// intent.getExtras().get("terminate");//
// intent.getStringExtra("terminate");
// Log.d("TAG", "service started");
//
// TelephonyManager telephony = (TelephonyManager)
// getSystemService(Context.TELEPHONY_SERVICE); // TelephonyManager
// // object
// CustomPhoneStateListener customPhoneListener = new
// CustomPhoneStateListener();
// telephony.listen(customPhoneListener,
// PhoneStateListener.LISTEN_CALL_STATE);
// context = getApplicationContext();
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
// if(terminate != null) {
// stopSelf();
// }
return START_NOT_STICKY;
}
public class CallBr extends BroadcastReceiver {
Bundle bundle;
String state;
String inCall, outCall;
public boolean wasRinging = false;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_IN)) {
if ((bundle = intent.getExtras()) != null) {
state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
wasRinging = true;
Toast.makeText(context, "IN : " + inCall, Toast.LENGTH_LONG).show();
} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
if (wasRinging == true) {
Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show();
String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
Log.d("TService", "onReceive: "+sampleDir);
String file_name = "Outgoing";
try {
audiofile = File.createTempFile(file_name, ".wav", sampleDir);
} catch (IOException e) {
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
recorder = new MediaRecorder();
// recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
// recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setOutputFile(audiofile.getAbsolutePath());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
recordstarted = true;
}
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
wasRinging = false;
Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
if (recordstarted) {
recorder.stop();
recordstarted = false;
}
}
}
} else if (intent.getAction().equals(ACTION_OUT)) {
if ((bundle = intent.getExtras()) != null) {
outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show();
File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
Log.d("TService", "onReceive: "+sampleDir);
String file_name = "Record";
try {
audiofile = File.createTempFile(file_name, ".wav", sampleDir);
} catch (IOException e) {
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
recorder = new MediaRecorder();
// recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
// recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setOutputFile(audiofile.getAbsolutePath());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
recordstarted = true;
}
}
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("callRecord"));
}
}
}
Receiver class:
public class DeviceAdminDemo extends DeviceAdminReceiver {
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
public void onEnabled(Context context, Intent intent) {
};
public void onDisabled(Context context, Intent intent) {
};
}
MainActivity Class
public class MainActivity extends Activity {
private static final int REQUEST_CODE = 0;
private DevicePolicyManager mDPM;
private ComponentName mAdminName;
private static final int PERMISSION_REQUEST_CODE= 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkPermission()){
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
}else{
requestPermission();
}
try {
// Initiate DevicePolicyManager.
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminName = new ComponentName(this, DeviceAdminDemo.class);
if (!mDPM.isAdminActive(mAdminName)) {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.");
startActivityForResult(intent, REQUEST_CODE);
} else {
// mDPM.lockNow();
// Intent intent = new Intent(MainActivity.this,
// TrackDeviceService.class);
// startService(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(receiver, new IntentFilter("callRecord"));
Intent intent = new Intent(MainActivity.this, TService.class);
startService(intent);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equalsIgnoreCase("callRecord")) {
Toast.makeText(MainActivity.this, "Call record", Toast.LENGTH_SHORT).show();
}
}
};
private boolean checkPermission(){
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
return true;
}else{
return false;
}
}
private void requestPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.ACCESS_COARSE_LOCATION)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.CALL_PHONE)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.SEND_SMS)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.READ_CONTACTS)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.READ_PHONE_STATE)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.RECORD_AUDIO)
|| ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAPTURE_AUDIO_OUTPUT)){
Toast.makeText(MainActivity.this,"Allow Us pemissions. Please allow in App Settings for additional functionality.",Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.CALL_PHONE, Manifest.permission.SEND_SMS, Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE,
Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAPTURE_AUDIO_OUTPUT}, PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission Granted, ", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission not Granted", Toast.LENGTH_SHORT).show();
}
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_CODE == requestCode) {
Intent intent = new Intent(MainActivity.this, TService.class);
startService(intent);
}
}
#Override
public void onResume() {
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, new IntentFilter("callRecord"));
super.onResume();
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.practice.callrecorder">
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".DeviceAdminDemo"
android:description="#string/app_name"
android:label="#string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="#xml/my_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
</intent-filter>
</receiver>
<service
android:name=".TService"
android:enabled="true"
android:exported="true">
</service>
</application>
my_admin.xml
<device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-policies>
<force-lock />
</uses-policies>
any help would be grateful!!!
Thanks in advance!!
use START_STICKY as return param of onStartCommand() so when you kill you app it will restart the service
for reference you can check android developer guide
https://developer.android.com/reference/android/app/Service.html
I want to retrieve the incoming/outgoing call's phone number, but sometimes the delivered phone number is null. I'm unable to reproduce it, but my clients are reporting that sometimes it's not working. I can confirm this because I have logs about this (~1000 times a day the phone number is empty).
I have 2 different BroadcastReceiver's which extends WakeLockBroadcast. The IntentServices are declared in Android's manifest file.
This is the outgoing call's receiver:
public class OutgoingCallReceiver extends WakeLockBroadcast {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, OutgoingCallReceiver.PhoneService.class);
if (intent != null && intent.getExtras() != null) {
service.setAction(intent.getAction());
Bundle bundle = new Bundle(intent.getExtras());
service.putExtras(bundle);
}
startWakefulService(context, service);
}
public static class PhoneService extends IntentService {
public PhoneService() {
super("PhoneService outgoing call");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
try {
if (intent != null) {
String action = intent.getAction();
if (action != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
if (action.equals("android.intent.action.NEW_OUTGOING_CALL")) {
String number = bundle.getString(Intent.EXTRA_PHONE_NUMBER, null);
onOutgoingCall(number);
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
catch (Error e) {
e.printStackTrace();
}
finally {
try {
if (intent != null)
completeWakefulIntent(intent);
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
}
private void onOutgoingCall(String number) {
if (TextUtils.isEmpty(number))
return;
Log.d(APPNAME, "Outgoing call: " + number);
}
}
}
This is the incoming call's receiver:
public class IncomingCallReceiver extends WakeLockBroadcast {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, IncomingCallReceiver.PhoneService.class);
if (intent != null && intent.getExtras() != null) {
service.setAction(intent.getAction());
Bundle bundle = new Bundle(intent.getExtras());
service.putExtras(bundle);
}
startWakefulService(context, service);
}
public static class PhoneService extends IntentService {
public PhoneService() {
super("PhoneService incoming call");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
try {
if (intent != null) {
String action = intent.getAction();
if (action != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
// Incoming call
if (action.equals("android.intent.action.PHONE_STATE")) {
String stateStr = bundle.getString(TelephonyManager.EXTRA_STATE, "");
String number = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER, "");
int state = 0;
if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
state = TelephonyManager.CALL_STATE_IDLE;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
state = TelephonyManager.CALL_STATE_OFFHOOK;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
}
if (state == TelephonyManager.CALL_STATE_IDLE) {
onCallEnd();
}
else if (state == TelephonyManager.CALL_STATE_RINGING) {
onIncomingCall(number);
}
}
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
catch (Error e) {
e.printStackTrace();
}
finally {
try {
if (intent != null)
completeWakefulIntent(intent);
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
}
private void onCallEnd() {
}
private void onIncomingCall(String phoneNumber) {
if (TextUtils.isEmpty(phoneNumber))
return;
Log.d("APPNAME", "Incoming call: " + phoneNumber);
}
}
}
The Android's manifest file:
<receiver android:name=".broadcast.IncomingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<receiver android:name=".broadcast.OutgoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
Services:
<service android:name=".broadcast.IncomingCallReceiver$PhoneService" />
<service android:name=".broadcast.OutgoingCallReceiver$PhoneService" />
I might think that the intent or the intent's bundle is empty. As you can see, I'm making a check before if intent or bundle is different than null and after that setting the data to the newly created intent.
I'm developing a sip client based on the SipDemo app. My app receives incoming calls successfully at first, but after some time my app cannot receive calls. BroadcastReceiver doesn't receive anything. What could cause this?
My manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kasenna.android.kasip">
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
<application android:icon="#drawable/icon" android:label="KaSip">
<activity android:name=".MainActivity"
android:launchMode="singleTask"
android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SipSettings" android:label="Настройки"/>
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>
<service android:name=".MainService" android:exported="false"/>
</application>
</manifest>
Main activity:
package com.kasenna.android.kasip;
public class MainActivity extends FragmentActivity implements
IncallFragmentClass.IncallButtonsEventListener,
IncallCallEndFragmentClass.IncallCallEndButtonsEventListener,
MakeCallFragmentClass.MakeCallButtonsEventListener,
DialpadFragmentClass.DialpadButtonsEventListener
{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.main);
mswitch=(Switch)findViewById(R.id.regswitch);
mswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked){
if(isChecked){
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String username=prefs.getString("namePref","");
String password=prefs.getString("passPref","");
if(username.length()==0||password.length()==0){
showDialog(UPDATE_SETTINGS_DIALOG);
}else {
accRegistered = true;
//registrationWorker("start");
initializeLocalProfile();
}
}else{
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String username=prefs.getString("namePref","");
String password=prefs.getString("passPref","");
if(username.length()==0||password.length()==0){
}else {
accRegistered = false;
//registrationWorker("stop");
closeLocalProfile();
}
}
}
});
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
AudioManager manager=(AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
manager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
Uri notification=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
ring = RingtoneManager.getRingtone(getApplicationContext(),notification);
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container_dialpad, (new DialpadFragmentClass())).commit();
ImageButton delButton = (ImageButton) findViewById(R.id.buttonDel);
delButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView labelView=(TextView)findViewById(R.id.sipLabelDialpad);
String currentString = labelView.getText().toString();
String needText = currentString.equals("") ? "" : currentString.substring(0,currentString.length()-1);
updateStatus(needText,true);
if((!currentString.equals(""))&(needText.equals(""))){
getSupportFragmentManager().beginTransaction().remove(mMakeCallClass).commit();
}
}
});
initializeManager();
}
public void initializeManager(){
IntentFilter filter = new IntentFilter();
filter.addAction("android.KaSip.INCOMING_CALL");
callReceiver = new IncomingCallReceiver();
this.registerReceiver(callReceiver,filter);
if(manager == null){
manager = SipManager.newInstance(this);
Log.v("KaSip_logs","manager created: "+manager.toString());
}
}
public void initializeLocalProfile(){
if(manager == null){
return;
}
if(me != null){
closeLocalProfile();
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String username = prefs.getString("namePref","");
String password = prefs.getString("passPref","");
try{
SipProfile.Builder builder = new SipProfile.Builder(username,"cgp.cittel.ru");
builder.setPassword(password);
ConnectivityManager connManager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi=connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if(mWifi.isConnected()){
builder.setProtocol("TCP");
}else{
builder.setProtocol("UDP");
}
builder.setSendKeepAlive(true);
builder.setAutoRegistration(true);
me=builder.build();
updateStatus("регистрация...");
Intent mServiceIntent = new Intent(this,MainService.class);
String dataUrl = me.getUriString();
mServiceIntent.setData(Uri.parse(dataUrl));
startService(mServiceIntent);
Intent i = new Intent();
i.setAction("android.KaSip.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this,0,i,Intent.FILL_IN_DATA);
Log.v("KaSip_logs","SipProfile="+me.getUriString());
manager.open(me,pi,null);
Log.v("KaSip_logs","after manager open");
SipRegistrationListener mListener = new SipRegistrationListener(){
public void onRegistering(String localProfileUri){
}
public void onRegistrationDone(String localProfileUri,long expiryTime){
updateStatus("зарегистрирован");
}
public void onRegistrationFailed(String localProfileUri,int errorCode,String errorMessage){
Log.v("KaSip_logs","SipRegistrationListener error="+errorMessage);
}
};
manager.setRegistrationListener(me.getUriString(),mListener);
manager.register(me,60,mListener);
Log.v("KaSip_logs","manager register");
}catch(ParseException pe){
pe.printStackTrace();
}catch(SipException se){
Log.v("KaSip_logs","SipException="+se.getMessage());
}
}
public void closeLocalProfile(){
if(manager==null){
return;
}
try{
if(me!=null){
manager.close(me.getUriString());
}
}catch(Exception ee){
ee.printStackTrace();
}
updateStatus("не зарегистрирован");
}
public void updatePreferences(){
Intent settingsActivity=new Intent(getBaseContext(),
SipSettings.class);
startActivity(settingsActivity);
}
public void onReceiveCallBroadcast(Intent intent){
SipAudioCall.Listener listener=new SipAudioCall.Listener(){
#Override
public void onRinging(SipAudioCall call,SipProfile caller){
super.onRinging(call,caller);
remoteCall=call;
Log.v("KaSip_logs","onReceiveCallBroadcast, onRinging, caller="+caller.getUriString());
}
#Override
public void onCallEnded(SipAudioCall call){
super.onCallEnded(call);
callTimer("stop");
updateStatus("", true);
if(ring.isPlaying()){
ring.stop();
}
if (loadedActionFragment.equals("incall")) {
getSupportFragmentManager().beginTransaction().remove(mIncallFragmentClass).commit();
loadedActionFragment = "";
}else if (loadedActionFragment.equals("incallcallstart")){
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
}
#Override
public void onCallEstablished(SipAudioCall call){
super.onCallEstablished(call);
callTimer("start");
createUI("incallcallstart");
}
#Override
public void onError(SipAudioCall call, int errorCode, String errorMessage){
super.onError(call,errorCode,errorMessage);
callTimer("stop");
updateStatus("",true);
if (loadedActionFragment.equals("incall")) {
getSupportFragmentManager().beginTransaction().remove(mIncallFragmentClass).commit();
loadedActionFragment = "";
}else if (loadedActionFragment.equals("incallcallstart")){
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
}
};
try{
incomingCall=manager.takeAudioCall(intent,listener);
}catch(SipException se){
Log.v("KaSip_logs","onReceiveCallBroadcast error="+se.getMessage());
if(incomingCall!=null){
incomingCall.close();
}
if(remoteCall!=null){
remoteCall.close();
}
}
Window window=this.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
ring.play();
updateStatus(incomingCall);
}
#Override
public void OnClick_buttonStart() {
updateStatus("",true);
if (ring.isPlaying()) {
ring.stop();
}
try {
if (remoteCall != null) {
remoteCall.answerCall(30);
}
incomingCall.answerCall(30);
incomingCall.startAudio();
if (incomingCall.isMuted()) {
incomingCall.toggleMute();
}
} catch (SipException se) {
Log.v("KaSip_logs", "onReceiveCallBroadcast error=" + se.getMessage());
if (incomingCall != null) {
incomingCall.close();
}
if (remoteCall != null) {
remoteCall.close();
}
}
}
#Override
public void OnClick_buttonStop() {
if (ring.isPlaying()) {
ring.stop();
}
try {
if (remoteCall != null) {
remoteCall.endCall();
}
if (incomingCall != null) {
incomingCall.endCall();
incomingCall.close();
}
if (remoteCall != null) {
remoteCall.close();
}
} catch (SipException se) {
Log.v("KaSip_logs", "onReceiveCallBroadcast error=" + se.getMessage());
}
callTimer("stop");
synchronized (this) {
try {
this.wait(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
updateStatus("", true);
getSupportFragmentManager().beginTransaction().remove(mIncallFragmentClass).commit();
loadedActionFragment = "";
}
#Override
public void OnClick_buttonCallEnd() {
try {
if (remoteCall != null) {
remoteCall.endCall();
}
if (incomingCall != null) {
incomingCall.endCall();
incomingCall.close();
}
if (outgoingCall != null) {
outgoingCall.endCall();
outgoingCall.close();
}
if (remoteCall != null) {
remoteCall.close();
}
} catch (SipException se) {
Log.v("KaSip_logs", "onReceiveCallBroadcast error=" + se.getMessage());
}
callTimer("stop");
generateRingback("stop");
updateStatus("", true);
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
#Override
public void OnClick_buttonMakeCall(){
if (accRegistered) {
createUI("incallcallstart");
TextView labelView = (TextView) findViewById(R.id.sipLabelDialpad);
sipAddress = labelView.getText().toString();
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onCallEstablished(SipAudioCall call) {
super.onCallEstablished(call);
generateRingback("stop");
call.startAudio();
callTimer("start");
updateStatus("", true);
}
#Override
public void onCallEnded(SipAudioCall call) {
super.onCallEnded(call);
callTimer("stop");
generateRingback("stop");
updateStatus("", true);
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
#Override
public void onCallBusy(SipAudioCall call) {
super.onCallBusy(call);
generateRingback("stop");
updateStatus("номер занят", true);
generateBusy("start");
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
#Override
public void onRingingBack(SipAudioCall call) {
super.onRingingBack(call);
updateStatus("ждём ответа", true);
generateRingback("start");
}
#Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
super.onError(call, errorCode, errorMessage);
callTimer("stop");
generateRingback("stop");
updateStatus("", true);
getSupportFragmentManager().beginTransaction().remove(mIncallCallEndFragmentClass).commit();
loadedActionFragment = "";
}
};
outgoingCall = manager.makeAudioCall(me.getUriString(), sipAddress + "#cgp.cittel.ru", listener, 30);
} catch (Exception e) {
e.printStackTrace();
if (me != null) {
try {
manager.close(me.getUriString());
} catch (Exception ee) {
ee.printStackTrace();
}
}
if (outgoingCall != null) {
outgoingCall.close();
}
}
}else{
Toast.makeText(this,"Сначала зарегистрируйтесь",Toast.LENGTH_LONG).show();
}
}
#Override
public void OnClick_buttonDialPad(final String button_description){
this.runOnUiThread(new Runnable(){
public void run(){
TextView labelView=(TextView)findViewById(R.id.sipLabelDialpad);
if ((loadedActionFragment.equals(""))&&(labelView.getText().toString().equals(""))){
mMakeCallClass = new MakeCallFragmentClass();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container_call_buttons, mMakeCallClass).commit();
}
updateStatus(labelView.getText()+button_description,true);
}
});
try {
if (incomingCall != null) {
if (button_description.equals("0")) {
incomingCall.sendDtmf(0);
} else if (button_description.equals("1")) {
incomingCall.sendDtmf(1);
} else if (button_description.equals("2")) {
incomingCall.sendDtmf(2);
} else if (button_description.equals("3")) {
incomingCall.sendDtmf(3);
} else if (button_description.equals("4")) {
incomingCall.sendDtmf(4);
} else if (button_description.equals("5")) {
incomingCall.sendDtmf(5);
} else if (button_description.equals("6")) {
incomingCall.sendDtmf(6);
} else if (button_description.equals("7")) {
incomingCall.sendDtmf(7);
} else if (button_description.equals("8")) {
incomingCall.sendDtmf(8);
} else if (button_description.equals("9")) {
incomingCall.sendDtmf(9);
} else if (button_description.equals("*")) {
incomingCall.sendDtmf(10);
} else if (button_description.equals("#")) {
incomingCall.sendDtmf(11);
} else if (button_description.equals("A")) {
incomingCall.sendDtmf(12);
} else if (button_description.equals("B")) {
incomingCall.sendDtmf(13);
} else if (button_description.equals("C")) {
incomingCall.sendDtmf(14);
} else if (button_description.equals("D")) {
incomingCall.sendDtmf(15);
}
}
if (outgoingCall != null) {
if (button_description.equals("0")) {
outgoingCall.sendDtmf(0);
} else if (button_description.equals("1")) {
outgoingCall.sendDtmf(1);
} else if (button_description.equals("2")) {
outgoingCall.sendDtmf(2);
} else if (button_description.equals("3")) {
outgoingCall.sendDtmf(3);
} else if (button_description.equals("4")) {
outgoingCall.sendDtmf(4);
} else if (button_description.equals("5")) {
outgoingCall.sendDtmf(5);
} else if (button_description.equals("6")) {
outgoingCall.sendDtmf(6);
} else if (button_description.equals("7")) {
outgoingCall.sendDtmf(7);
} else if (button_description.equals("8")) {
outgoingCall.sendDtmf(8);
} else if (button_description.equals("9")) {
outgoingCall.sendDtmf(9);
} else if (button_description.equals("*")) {
outgoingCall.sendDtmf(10);
} else if (button_description.equals("#")) {
outgoingCall.sendDtmf(11);
} else if (button_description.equals("A")) {
outgoingCall.sendDtmf(12);
} else if (button_description.equals("B")) {
outgoingCall.sendDtmf(13);
} else if (button_description.equals("C")) {
outgoingCall.sendDtmf(14);
} else if (button_description.equals("D")) {
outgoingCall.sendDtmf(15);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private class generateRingbackTask extends AsyncTask<Void, Void, Void> {
Context mContext;
public generateRingbackTask(Context context) {
super();
mContext = context;
}
#Override
protected Void doInBackground(Void... voids) {
int counter = 0;
ToneGenerator mRingback = new ToneGenerator(0,ToneGenerator.MAX_VOLUME);
synchronized (this) {
while (!this.isCancelled()) {
mRingback.startTone(ToneGenerator.TONE_SUP_DIAL,1000);
try {
this.wait(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
mRingback.stopTone();
try {
this.wait(1500);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
counter = counter + 2;
}
}
return null;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void generateRingback(String action){
if(action.equals("start")){
synchronized(this){
mringbackTask = new generateRingbackTask(this);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mringbackTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
mringbackTask.execute();
}
}
}else{
if (mringbackTask !=null){
mringbackTask.cancel(true);
}
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void generateBusy(String action){
if(action.equals("start")){
synchronized(this){
mbusyTask = new generateBusyTask(this);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mbusyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
mbusyTask.execute();
}
}
}else{
if (mbusyTask !=null){
mbusyTask.cancel(true);
}
}
}
private class generateBusyTask extends AsyncTask<Void, Void, Void> {
Context mContext;
public generateBusyTask(Context context) {
super();
mContext = context;
}
#Override
protected void onPostExecute(Void voids) {
updateStatus("", true);
}
#Override
protected Void doInBackground(Void... voids) {
int counter;
ToneGenerator mBusy = new ToneGenerator(0,ToneGenerator.MAX_VOLUME);
synchronized (this) {
for(counter=0;counter<5;counter++){
mBusy.startTone(ToneGenerator.TONE_SUP_DIAL,300);
try {
this.wait(300);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
mBusy.stopTone();
try {
this.wait(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
return null;
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void registrationWorker(String action){
if(action.equals("start")){
synchronized(this){
mregistrationTask = new registrationWorkerTask(this);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mregistrationTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
mregistrationTask.execute();
}
}
}else{
if (mregistrationTask !=null){
mregistrationTask.cancel(true);
}
}
}
private class registrationWorkerTask extends AsyncTask<Void, Void, Void> {
Context mContext;
public registrationWorkerTask(Context context) {
super();
mContext = context;
}
#Override
protected void onPreExecute(){
if ((callReceiver == null)&&(manager == null)){
initializeManager();
}
}
#Override
protected void onProgressUpdate(Void... voids){
initializeLocalProfile();
}
#Override
protected Void doInBackground(Void... voids) {
synchronized (this) {
while (!this.isCancelled()) {
publishProgress(null);
try {
this.wait(58000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
Log.v("KaSip_logs", "registrationWorkerTask stopped");
return null;
}
}
}
and IncomingCallRecever.java:
package com.kasenna.android.kasip;
public class IncomingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,
MainActivity.class);
context.startActivity(i);
MainActivity mainActivity = (MainActivity) context;
mainActivity.createUI("incall");
mainActivity.onReceiveCallBroadcast(intent);
}
}
I developed an application for a customer to internet calling using sip.For that he provided me two valid sip user_id and password. Am Using SIP API for SIP implementation.customer says that the call is not going.he don't get any notification about missed calls when he logged using his account.i cant find any mistakes in the code.please help me .the code is given below.
public class CallActivity extends Activity {
public String sipAddress = null;
public SipManager mSipManager = null;
public SipProfile mSipProfile = null;
public SipAudioCall call = null;
Button b1;
TextView sipadd;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.calling);
sipAddress = (String) getIntent().getExtras().get("sipAddress");
b1 = (Button) findViewById(R.id.sipcallbtnend);
b1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
sipadd = (TextView) findViewById(R.id.sipcalltvdialedaddress);
sipadd.setText(sipAddress);
b1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (call != null) {
call.close();
}
finish();
}
});
initializeManager();
}
#Override
public void onStart() {
super.onStart();
// When we get back from the preference setting Activity, assume
// settings have changed, and re-login with new auth info.
initializeManager();
}
#Override
public void onDestroy() {
super.onDestroy();
if (call != null) {
call.close();
}
closeLocalProfile();
// if (callReceiver != null) {
// this.unregisterReceiver(callReceiver);
// }
}
public void initializeManager() {
if (mSipManager == null) {
mSipManager = SipManager.newInstance(this);
}
initializeLocalProfile();
}
public void initializeLocalProfile() {
if (mSipManager == null) {
return;
}
if (mSipProfile != null) {
closeLocalProfile();
}
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
String username = prefs.getString("namePref", "");
String domain = prefs.getString("domainPref", "");
String password = prefs.getString("passPref", "");
if (username.length() == 0 || domain.length() == 0
|| password.length() == 0) {
// showDialog(UPDATE_SETTINGS_DIALOG);
return;
}
try {
SipProfile.Builder builder = new SipProfile.Builder(username,
domain);
builder.setPassword(password);
builder.setDisplayName(username);
builder.setAuthUserName(username);
mSipProfile = builder.build();
Intent i = new Intent();
i.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i,
Intent.FILL_IN_DATA);
mSipManager.open(mSipProfile, pi, null);
//
//
// // This listener must be added AFTER manager.open is called,
// // Otherwise the methods aren't guaranteed to fire.
mSipManager.setRegistrationListener(mSipProfile.getUriString(),
new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
// updateStatus("Registering with SIP Server...");
Log.d("onRegistering",
"Registering with SIP Server...");
}
public void onRegistrationDone(String localProfileUri,
long expiryTime) {
// updateStatus("Ready");
Log.d("onRegistrationDone",
"RegistrationDone..Ready");
}
public void onRegistrationFailed(
String localProfileUri, int errorCode,
String errorMessage) {
// updateStatus("Registration failed. Please check settings.");
Log.d("onRegistrationFailed", "RegistrationFailed");
}
});
} catch (ParseException pe) {
// updateStatus("Connection Error.");
} catch (SipException se) {
// updateStatus("Connection error.");
}
initiateCall();
}
public void closeLocalProfile() {
if (mSipManager == null) {
return;
}
try {
if (mSipProfile != null) {
mSipManager.close(mSipProfile.getUriString());
}
} catch (Exception ee) {
Log.d("WalkieTalkieActivity/onDestroy",
"Failed to close local profile.", ee);
}
}
public void initiateCall() {
// updateStatus(sipAddress);
Log.d("nzm", "initiatecall");
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
// Much of the client's interaction with the SIP Stack will
// happen via listeners. Even making an outgoing call, don't
// forget to set up a listener to set things up once the call is
// established.
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
Log.d("on call established", "on call established");
// updateStatus(call);
}
#Override
public void onCallEnded(SipAudioCall call) {
// updateStatus("Ready.");
// Intent i = new
// Intent(getBaseContext(),DialActivity.class);
// startActivity(i);
finish();
}
};
call = mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress,
listener, 3000);
Log.d("call", "" + call.getState());
} catch (Exception e) {
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", e);
if (mSipProfile != null) {
try {
mSipManager.close(mSipProfile.getUriString());
} catch (Exception ee) {
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
}
The permissions in manifest is given below
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
please help me .Thanks in Advance.
Maybe add these
<uses-permission android:name="android.permission.CONFIGURE_SIP" />
<uses-feature android:name="android.software.sip" android:required="true" />
<uses-feature android:name="android.software.sip.voip" android:required="true" />
<uses-feature android:name="android.hardware.telephony" android:required="false" />
Are you using the android's example? It should work on device that support SIP.
And add receiver in onCreate
IntentFilter filter = new IntentFilter();
filter.addAction("android.SipDemo.INCOMING_CALL");
callReceiver = new IncomingCallReceiver();
this.registerReceiver(callReceiver, filter);
Do you have this in manifest?:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>
See:
https://developer.android.com/guide/topics/connectivity/sip.html
and
https://android.googlesource.com/platform/development/+/master/samples/SipDemo/