I have build an audioplayer which is deployed in android google playstore. I'm using crashlytics to monitor crashes and ANRs. Recently I have been getting a lot of crashes MediaButtonReceiver. The headset clicks work fine in many devices. But some devices are giving this problem.
Crashlytics report -
Fatal Exception: java.lang.RuntimeException: Unable to start receiver android.support.v4.media.session.MediaButtonReceiver: java.lang.IllegalStateException: Could not find any Service that handles android.intent.action.MEDIA_BUTTON or implements a media browser service.
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2866)
at android.app.ActivityThread.access$1700(ActivityThread.java:182)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1551)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5706)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1033)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
MediaSession code -
private void initMediaSession() throws RemoteException {
if (mediaSessionManager != null) return; //mediaSessionManager exists
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaSessionManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
}
// Create a new MediaSession
mediaSession = new MediaSessionCompat(this, "AudioPlayer");
//Get MediaSessions transport controls
transportControls = mediaSession.getController().getTransportControls();
//set MediaSession -> ready to receive media commands
mediaSession.setActive(true);
//indicate that the MediaSession handles transport control commands
// through its MediaSessionCompat.Callback.
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS|MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
//Set mediaSession's MetaData
updateMetaData();
mediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
resumeMedia();
}
#Override
public void onPause() {
super.onPause();
pauseMedia();
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
}
#Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
}
#Override
public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
if (su.getHeadsetEnableSwitch()) {
String intentAction = mediaButtonIntent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
KeyEvent event = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event != null) {
int action = event.getAction();
Log.e("Headset key: ", String.valueOf(action));
if (action == KeyEvent.ACTION_DOWN) {
Log.e("Headset: ", "Action down");
headsetClickCount++;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (headsetClickCount == 1) {
if (isPng()) pauseMedia();
else resumeMedia();
headsetClickCount = 0;
} else if (headsetClickCount == 2) {
if (su.getDoubleClickAction() == 0) {
} else if (su.getDoubleClickAction() == 1)
skipToPrevious();
else if (su.getDoubleClickAction() == 2) skipToNext();
headsetClickCount = 0;
} else if (headsetClickCount == 3) {
if (su.getTripleClickAction() == 0) {
} else if (su.getTripleClickAction() == 1)
skipToPrevious();
else if (su.getTripleClickAction() == 2) skipToNext();
headsetClickCount = 0;
}
}
}, 750);
}
if (action == KeyEvent.FLAG_LONG_PRESS) {
if (su.getLongClickAction() == 0) {
} else if (su.getLongClickAction() == 1) skipToPrevious();
else if (su.getLongClickAction() == 2) skipToNext();
}
if (action == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
Log.e("Headset: ", "headset sethook");
if (isPng()) pauseMedia();
else resumeMedia();
}
if (action == KeyEvent.KEYCODE_MEDIA_NEXT) {
skipToNext();
}
if (action == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
skipToPrevious();
}
if (action == KeyEvent.KEYCODE_MEDIA_PAUSE) {
pauseMedia();
}
if (action == KeyEvent.KEYCODE_MEDIA_PLAY) {
resumeMedia();
}
}
}
return true;
}
return true;
}
});
}
What could be the problem and how to solve this?
My thoughts - Maybe this happens because user opens other music apps that has this feature while my app is still playing.
You have to create your own media button receiver class, say MyMediaButtonReceiver.java, that extends MediaButtonReceiver, and it will be empty except for the onReceive method that you have to override, calling super.onReceive(...) between a try-catch that captures the IllegalStateException:
public class MyMediaButtonReceiver extends MediaButtonReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
super.onReceive(context, intent);
} catch (IllegalStateException e) {
Log.d(this.getClass().getName(), e.getMessage());
}
}
}
Then you have to declare that receiver class in your Manifest (or replace your previous MediaButtonReceiver class declaration, if you had one), like:
<receiver android:name=".MyMediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
class MyMediaButtonReceiver : MediaButtonReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_MEDIA_BUTTON) {
val event = intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
if (event.action == KeyEvent.ACTION_UP || event.action ==
KeyEvent.ACTION_DOWN) {
when (event.keyCode) {
// handle cancel button
KeyEvent.KEYCODE_MEDIA_STOP -> context.sendIntent(ACTION_FINISH)
// handle play button
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PAUSE -> context.sendIntent(ACTION_PLAY_PAUSE)
}
}
}
}
}
kotlin extension for send event to media service
fun Context.sendIntent(action: String) {
Intent(this, MediaPlayerService::class.java).apply {
this.action = action
try {
if (isOreoPlus()) {
startForegroundService(this)
} else {
startService(this)
}
} catch (ignored: Exception) {
}
}
}
add Receiver in manifest
<receiver android:name=".player.receivers.MyMediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Related
I am making a default phone call. Everything works well till I made a call to the switchboard operator.
In this kind of call, the phone says: "Press 1 to do A, press 2 to do B".
I did some research for hours but couldn't find one...
I did try this code, but it doesn't work.
keyPressed(KeyEvent.KEYCODE_1); // when press key 1
private void keyPressed(int keyCode) {
....
Intent i = new Intent(Intent.ACTION_CALL, Uri.parse("tel://" + keyCode));
startActivity(I);
....
playTone(ToneGenerator.TONE_DTMF_1, TONE_LENGTH_INFINITE);
}
Big thanks for any of your suggestions!
Added 1:
I am using InCallService like this:
class CallService : InCallService() {
private var isShowEnded = true
override fun onCallAdded(call: Call) {
super.onCallAdded(call)
OngoingCall().setCall(call)
CallActivity.getInstance().start(this, call)
isShowEnded = false
}
override fun onCallRemoved(call: Call) {
super.onCallRemoved(call)
OngoingCall().setCall(null)
}
}
and OngoingCall:
public class OngoingCall {
public static BehaviorSubject<Integer> state = BehaviorSubject.create();
private static Call sCall;
public Call getsCall() {
return sCall;
}
#RequiresApi(api = Build.VERSION_CODES.M)
private Object callback = new Call.Callback() {
#Override
public void onStateChanged(Call call, int newState) {
super.onStateChanged(call, newState);
state.onNext(newState);
}
};
#RequiresApi(api = Build.VERSION_CODES.M)
public final void setCall(#Nullable Call value) {
if (sCall != null) {
sCall.unregisterCallback((Call.Callback) callback);
}
if (value != null) {
value.registerCallback((Call.Callback) callback);
state.onNext(value.getState());
}
sCall = value;
}
#RequiresApi(api = Build.VERSION_CODES.M)
public void answer() {
if (sCall != null) {
assert sCall != null;
sCall.answer(VideoProfile.STATE_AUDIO_ONLY);
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
public void hold(boolean hold) {
if (sCall != null) {
if (hold) sCall.hold();
else sCall.unhold();
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
public void addCall(Call call) {
if (sCall != null) {
sCall.conference(call);
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
public void hangup() {
if (sCall != null) {
sCall.disconnect();
}
}
}
And then I tried this when pressing keyboard:
mTrueCallerOngoingCall.getsCall().playDtmfTone((char) tone); // inside playTone()
But it's still not working :(
Update 2:
I have fixed my adding this method:
private char getChar(int tone) {
if (tone == 0) return '0';
else if (tone == 1) return '1';
else if (tone == 2) return '2';
else if (tone == 3) return '3';
else if (tone == 4) return '4';
else if (tone == 5) return '5';
else if (tone == 6) return '6';
else if (tone == 7) return '7';
else if (tone == 8) return '8';
else if (tone == 9) return '9';
else if (tone == 10) return '*';
else return '#';
}
and change from my above code to
mTrueCallerOngoingCall.getsCall().playDtmfTone(getChar(tone));
mTrueCallerOngoingCall.getsCall().stopDtmfTone();
It is .Hope can help you.
call.playDtmfTone(char);
The call PATH:
android.telecom.Call;
From: Any Class extends InCallService.
In Method: onCallAdded(call);
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 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 have a handler inside oncreate of an activity. It receives a value from handler.sendEmptyMessage.
handleMessage is fired and it reaches till the line where I try to update the textview as shown below:
mImageCountText.setText("" + mCountText);
But the text of textview never gets changed. What am I missing here?
Is there anything obvious that causes this issue?
Any help is much appreciated.
EDIT
Handler code
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
final int what = msg.what;
if (what == Constants.HANDLER_APP_UPDATE) {
if (!UserHelper.isAppBuildVerionSameAsUpdate(HomeActivity.this)) {
updateNotificationAlert();
showAppUpdatePopUp();
}
} else if (what == Constants.HANDLER_COLLECTION_UPDATE) {
//TODO: Refresh collection
} else {
mCountText = what;
if (!Utils.isTablet()) {
if (mCountText == 0) {
mImageCountText.setVisibility(View.INVISIBLE);
} else {
mImageCountText.setVisibility(View.VISIBLE);
mImageCountText.setText("" + mCountText); // this does not work
}
} else {
if (mCountText == 0) {
mCollectionsFragment.refreshAfterUpload();
mCountTextForUplaod.setVisibility(View.INVISIBLE);
} else {
mCollectionsFragment.refreshAfterUpload();
mCountTextForUplaod.setVisibility(View.VISIBLE);
mCountTextForUplaod.setText("" + mCountText);
}
}
}
}
};
Onreceive from where value is sent
#Override
public void onReceive(final Context context, final Intent intent) {
Runnable runnable = new Runnable() {
public void run() {
if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_INTENT_FILTER)) {
boolean broadcastStatus = intent.getBooleanExtra(Constants.BROADCAST_DATA_STATUS, false);
String broadcastStatusMessage = intent.getStringExtra(Constants.BROADCAST_DATA_STATUS_MESAGE);
if (broadcastStatus) {
mCountText = PreferenceHelper.getFromPreference(context, Constants.RECENT_IMAGES_COUNT, 0);
handler.sendEmptyMessage(PreferenceHelper.getFromPreference(context, Constants.RECENT_IMAGES_COUNT, 0));
}
} else {
if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_ACTION_APP_UPDATE)) {
handler.sendEmptyMessage(Constants.HANDLER_APP_UPDATE);
} else if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_ACTION_COLLECTION_UPDATE)) {
handler.sendEmptyMessage(Constants.HANDLER_COLLECTION_UPDATE);
}
}
}
};
Thread mythread = new Thread(runnable);
mythread.start();
Your code is too complex. You don't need the handler and definitively not the thread. Thy it like this:
#Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_INTENT_FILTER)) {
boolean broadcastStatus = intent.getBooleanExtra(Constants.BROADCAST_DATA_STATUS, false);
String broadcastStatusMessage = intent.getStringExtra(Constants.BROADCAST_DATA_STATUS_MESAGE);
if (broadcastStatus) {
mCountText = PreferenceHelper.getFromPreference(context, Constants.RECENT_IMAGES_COUNT, 0);
if (mCountText == 0) {
mCollectionsFragment.refreshAfterUpload();
mCountTextForUplaod.setVisibility(View.INVISIBLE);
} else {
mCollectionsFragment.refreshAfterUpload();
mCountTextForUplaod.setVisibility(View.VISIBLE);
mCountTextForUplaod.setText("" + mCountText);
}
}
} else {
if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_ACTION_APP_UPDATE)) {
if (!UserHelper.isAppBuildVerionSameAsUpdate(HomeActivity.this)) {
updateNotificationAlert();
showAppUpdatePopUp();
}
} else if (intent.getAction() != null && intent.getAction().equals(Constants.BROADCAST_ACTION_COLLECTION_UPDATE)) {
// TODO
}
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_UP) {
//TODO
}
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
//TODO
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
This code is working when screen is on. But not when screen is locked. Is there a way to get the volume key event when the screen is locked?
The event only trigger when the screen is on..other wise root permission is needed.
Make a BroadcastReceiver extended class
public class YourBoardcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("get something", "i dont know what!!");
String intentAction = intent.getAction();
KeyEvent event = null;
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
event = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
}
if (event == null) {
return;
}
int keycode = event.getKeyCode();
int action = event.getAction();
long eventtime = event.getEventTime();
if (keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|| keycode == KeyEvent.KEYCODE_HEADSETHOOK) {
if (action == KeyEvent.ACTION_DOWN) {
// Start your app here!
// ...
Log.e("event/////", "Trigerd");
if (isOrderedBroadcast()) {
abortBroadcast();
}
}
}
}
}
}
And in your Manifest :
<receiver android:name="YourBoardcastReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</receiver>
and Call it like this.
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mRemoteControlResponder = new ComponentName(getPackageName(),
YourBoardcastReceiver.class.getName());