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.
Related
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
I am using SMS Retriever API to get OTP but the problem I am facing is that it is not receiving SMS every time. Sometime SMS content is retrieved and some time nothing happens.
I have used the Toast (Broadcaster started) to show if it is started every time but Toast is also not displayed every time. I am unable to diagnose the problem.
Broadcast Receiver code:
public class OTPBroadcastReceiver extends BroadcastReceiver {
private String otp;
private static OTPSMSReceiveListner otpsmsReceiveListner = null;
private final Pattern p = Pattern.compile("(|^)\\d{4}");
public static void injectListner(OTPSMSReceiveListner listner){
otpsmsReceiveListner = listner;
}
#Override
public void onReceive(Context context, Intent intent) {
try {
Toast.makeText(context,"Broadcaster started",Toast.LENGTH_LONG).show();
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch (status.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
//Toast.makeText(context,"success",Toast.LENGTH_LONG).show();
// Get SMS message contents
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
if (message != null) {
Matcher m = p.matcher(message);
if (m.find()) {
otp = m.group(0);
}
String token;
try {
token = CommonMethods.getSecurePref("OTP", context);
} catch (Exception ex) {
token = null;
}
if (token == null) {
//Pass on the text to our listener.
otpsmsReceiveListner.onOTPReceived(otp);
}
}
break;
case CommonStatusCodes.TIMEOUT:
Log.d("onReceive", "timed out (5 minutes)");
//Toast.makeText(context,"Timeout",Toast.LENGTH_LONG).show();
otpsmsReceiveListner.onOTPTimeout();
break;
}
}
}
catch (Exception ex){
Toast.makeText(context,ex.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}
}
public interface OTPSMSReceiveListner{
void onOTPReceived(String otp);
void onOTPTimeout();
}
}
OTP class:
SmsRetrieverClient client = SmsRetriever.getClient(mContext);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
try
{
Log.e("onSuccess","Successfully started retriever");
}
catch (Exception ex)
{
Log.e("onSuccess",ex.getMessage());
}
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e("onFailure", "Failed to start retriever");
}
});
OTPBroadcastReceiver.injectListner(new OTPBroadcastReceiver.OTPSMSReceiveListner() {
#Override
public void onOTPReceived(String otp) {
if(otp.length() == 4) {
otpField.setText(otp);
btnVerify.performClick();
}
}
#Override
public void onOTPTimeout() {
Log.e("onOTPTimeout","onOTPTimeout");
}
});
Manifest:
<receiver
android:name=".helpers.OTPBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" />
</intent-filter>
</receiver>
SMS:
<#> your App OTP is:8149 585dyDy8cbh
See this answer https://stackoverflow.com/a/55374780/10449332. Please register the BroadcastReceiver inside SmsRetriever addOnSuccessListener callback.
I have a boot receiver starting a service and also I can start and stop the service within the app.
But when I boot up the phone the service does start but stops instantly after starting. I have set the return on onStartCommand to START_STICKY.
This is my boot receiver:
public void onReceive(final Context context, final Intent intent) {
if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){
Toast.makeText(context, "Boot received", Toast.LENGTH_LONG).show();
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
this.mTelephonyMgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
this.encryption = new Encryption(mTelephonyMgr, sharedPreferences);
//startService(context);
Intent i = new Intent(context, ProfileActivity.class);
i.putExtra("boot_received", false);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
sharedPreferences.edit().putBoolean(Keys.AVAILABILITY, false).apply();
}
}
public void startService(final Context context){
final Intent intent = new Intent(context, PhoneCallService.class);
// If no token, try getting one.
if (Keys.phoneServiceToken == null || Keys.phoneServiceToken.isEmpty()) {
getToken(context, new Callbacks.ReceivePhoneServiceTokenCallback() {
#Override
public void receivePhoneServiceTokenCallback(boolean gotToken) {
if (gotToken) {
intent.putExtra(Keys.PHONE_SERVICE_TOKEN_EXTRA, Keys.phoneServiceToken);
intent.setAction(PhoneCallService.START_SERVICE);
context.startService(intent);
} else {
Log.d(LOG_TAG, String.valueOf(R.string.unexpected_error));
}
}
});
} else {
intent.putExtra(Keys.PHONE_SERVICE_TOKEN_EXTRA, Keys.phoneServiceToken);
intent.setAction(PhoneCallService.START_SERVICE);
context.startService(intent);
}
}
public void getToken(Context context, final Callbacks.ReceivePhoneServiceTokenCallback callback){
final String API = Keys.getpvmURL() + SharedResources.URL_DIRECT_CALL_TOKEN;
JsonObject json = encryption.getID();
json.addProperty("versionCode", BuildConfig.VERSION_CODE);
Ion.with(context)
.load(API)
.setTimeout(Keys.TIMEOUT_DIRECT_CALL_TOKEN)
.setJsonObjectBody(json)
.asJsonObject()
.withResponse()
.setCallback(new FutureCallback<Response<JsonObject>>() {
#Override
public void onCompleted(Exception e, Response<JsonObject> result) {
if(e == null) {
Log.d(LOG_TAG, "No Exceptions");
if(result.getHeaders().code() == 200) {
if(result.getResult().has("result")) {
Keys.phoneServiceToken = result.getResult().get("result").getAsString();
callback.receivePhoneServiceTokenCallback(true);
} else {
Log.w(LOG_TAG, "Does not have result");
callback.receivePhoneServiceTokenCallback(false);
}
} else {
Log.w(LOG_TAG, "Not getting 200 " + result.getHeaders().message());
callback.receivePhoneServiceTokenCallback(false);
}
} else {
Log.e(LOG_TAG, "Exception has occurred " + e.getClass());
callback.receivePhoneServiceTokenCallback(false);
}
}
});
This is my onStart and onCreate methods:
#Override
public void onCreate() {
Log.d(LOG_TAG, "Service started");
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(PhoneCallService.this);
notificationManager = (NotificationManager) PhoneCallService.this.getSystemService(Context.NOTIFICATION_SERVICE);
voiceBroadcastReceiver = new VoiceBroadcastReceiver();
registerReceiver();
audioManager = (AudioManager) PhoneCallService.this.getSystemService(Context.AUDIO_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent == null || intent.getAction() == null) {
Log.d(LOG_TAG, "No Action");
}
else if (intent.getAction().equals(START_SERVICE)) {
Log.d(LOG_TAG, "Starting PhoneCallService");
accessToken = intent.getStringExtra(Keys.PHONE_SERVICE_TOKEN_EXTRA);
Log.d(LOG_TAG, accessToken);
if (accessToken != null && !accessToken.isEmpty()) {
registerForCallInvites();
MyFcmListenerService.availableToCall = true;
} else {
stopSelf();
MyFcmListenerService.availableToCall = false;
}
}
else if (intent.getAction().equals(STOP_SERVICE)) {
stopSelf();
MyFcmListenerService.availableToCall = false;
}
else if (intent.getAction().equals(ACTION_INCOMING_CALL)) {
handleIncomingCallIntent(intent);
}
else {
Log.d(LOG_TAG, intent.getAction());
}
return START_STICKY;
}
For some reason I just can't get it to work on the boot request.
I am trying to read incoming message using receiver.I followed tutorial and added below code but broadcast receiver is not getting fired.Log placed inside onReceive never gets fired.
Manifest
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application
android:name=".xyz"
android:allowBackup="true"
android:icon="#mipmap/icon_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<receiver android:name="xyz.receiver.SmsReceiver">
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
BroadcastReceiver
public class SmsReceiver extends BroadcastReceiver {
private static SmsListener mListener;
#Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getExtras();
Log.e("TEST",data.toString());
Object[] pdus = (Object[]) data.get("pdus");
for(int i=0;i<pdus.length;i++){
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
String sender = smsMessage.getDisplayOriginatingAddress();
String messageBody = smsMessage.getMessageBody();
mListener.messageReceived(messageBody);
}
}
public static void bindListener(SmsListener listener) {
mListener = listener;
}
}
Activity
SmsReceiver.bindListener(new SmsListener() {
#Override
public void messageReceived(String messageText) {
Toast.makeText(OTPActivity.this, "Message: " + messageText, Toast.LENGTH_LONG).show();
}
});
I have used this code, hope this works for you too :)
private BroadcastReceiver mSMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
try {
Log.e("sms receiver", "0000sdfghjkjhgfdsdfghjk");
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
String sms;
for (Object pdu : pdus) {
SmsMessage tmp;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
tmp = SmsMessage.createFromPdu((byte[]) pdu, bundle.getString("format"));
} else {
tmp = SmsMessage.createFromPdu((byte[]) pdu);
}
String senderMobile = tmp.getMessageBody();
sms = tmp.getMessageBody();
if (senderMobile.startsWith("کد فعالسازی شما در توپ 360:")) {
Log.e("sms receiver", "1111sdfghjkjhgfdsdfghjk");
final String mSMS = sms.replaceAll("[^0-9]", "");
//TODO Check SMS Center number with senderMobile if(senderMobile.equals(989100000)){...}
if (mSMS.length() == 5 || mSMS.length() == 6) {
Log.e("sms receiver", "2222sdfghjkjhgfdsdfghjk");
runOnUiThread(new Runnable() {
#Override
public void run() {
//CODE IS mSMS
code.setText(mSMS);
Log.e("sms receiver", "3333sdfghjkjhgfdsdfghjk");
}
});
abortBroadcast();
break;
}
}
}
}
}
} catch (Exception e) {
Log.e("sms exception", e.getMessage());
}
}
};
#Override
public void onResume() {
super.onResume();
if (isGranted) {
IntentFilter mIntentFilter = new IntentFilter();
Log.e("sms receiver", "4444sdfghjkjhgfdsdfghjk");
mIntentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
mIntentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(mSMSReceiver, mIntentFilter);
} else {
Log.e("sms receiver", "5555sdfghjkjhgfdsdfghjk");
}
}
#Override
public void onPause() {
super.onPause();
if (isRegistered) {
unregisterReceiver(mSMSReceiver);
Log.e("sms receiver", "6666sdfghjkjhgfdsdfghjk");
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 100: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
isGranted = true;
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
mIntentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(mSMSReceiver, mIntentFilter);
Log.e("sms receiver", "7777sdfghjkjhgfdsdfghjk");
isRegistered = true;
onResume();
} else {
isGranted = false;
Snackbar snackbar = Snackbar.make(coordinatorLayout, "دریافت کننده خودکار پیامک غیرفعال است.", Snackbar.LENGTH_LONG);
snackbar.show();
}
return;
}
}
}
I have been trying to listen to Battery BroadCast events. Plugged/Unplugged.
public class BatteryReceiver extends BroadcastReceiver {
public BatteryReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if(status == BatteryManager.BATTERY_STATUS_CHARGING){
Toast.makeText(context, "Charging", Toast.LENGTH_SHORT).show();
} else if(status == BatteryManager.BATTERY_STATUS_DISCHARGING || status == BatteryManager.BATTERY_STATUS_NOT_CHARGING){
Toast.makeText(context, "Not charging", Toast.LENGTH_SHORT).show();
}
}
}
I have added the manifest actions :
<receiver
android:name=".BatteryReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
If you want to track when it is plugged/unplugged only, I think you can check the Intent received.
public class BatteryReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent != null) {
String action = intent.getAction();
if(action != null) {
if(action.equals("android.intent.action.ACTION_POWER_CONNECTED"){
Toast.makeText(context, "Charging", Toast.LENGTH_SHORT).show();
} else if(action.equals("android.intent.action.ACTION_POWER_DISCONNECTED"){
Toast.makeText(context, "Not charging", Toast.LENGTH_SHORT).show();
}
}
}
}
}
UPDATE
But if you really want to check if Battery is Charging, you must change your code.
First, I notice that when you register your BroadcastReceiver via AndroidManifest.xml, intent received does not have any extra (in log, it would appear hasExtras when you print the intent:
Intent { act=android.intent.action.ACTION_POWER_DISCONNECTED flg=0x4000010 cmp=com.pivoto.myapplication/.BootCompletedReceiver }
Intent { act=android.intent.action.ACTION_POWER_CONNECTED flg=0x4000010 cmp=com.pivoto.myapplication/.BootCompletedReceiver }
Then, I searched in StackOverflow and I found this ANSWER (please, check it for more details):
So, is there a way to "request" the battery status when you want:
public class BootCompletedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent != null) {
Intent oneTimeOnlyBatteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int status = -1;
if(oneTimeOnlyBatteryIntent != null)
status = oneTimeOnlyBatteryIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if(status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL) {
Toast.makeText(context, "Charging", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Not charging", Toast.LENGTH_SHORT).show();
}
}
}
}