Android Question SOLVED: How to use PhoneStatusChanged

udg

Expert
Licensed User
Longtime User
Hi all,

I read most of the threads about PSC but I can't still make it work for me.
My code looks like the following:
B4X:
' in a toggle button event as part of Main
Sub btnDND_CheckedChange(Checked As Boolean)
   If Checked Then
     StartService(svc_dnd)
   Else
    StopService(svc_dnd)
   End If   
End Sub


'Service module: svc_dnd

Sub Process_Globals
  Dim PhoneId As PhoneId
  Dim PE As PhoneEvents
  Dim p As Phone
  Dim sNotif As Notification
End Sub

Sub Service_Create
  PE.InitializeWithPhoneState("PE", PhoneId)
  p.SetMute(p.VOLUME_RING,True)
  sNotif.Initialize
  sNotif.Icon = "icon"
  sNotif.SetInfo("DND","Service Running",Main)
  sNotif.Sound = False
  sNotif.Vibrate = False
  sNotif.Notify(1)
  Service.StartForeground(1,sNotif) 'ok notification fires
End Sub

Sub Service_Start(StartingIntent As Intent)
  Log("start: "&StartingIntent) 'ok this one fires
End Sub

Sub Service_Destroy
  PE.StopListening  'used when I call StopService from main
End Sub

Sub PE_PhoneStatusChanged(State As String, IncomingNumber As String, Intent As Intent)
  Log("status: "&State)                  'NO. it never fires!!
   Log("number: "&IncomingNumber)
   Log("intent: "&Intent)
  If State ="RINGING" Then
    Log("ringing")                          'NO. never fires
    p.SetMute(p.VOLUME_RING,False)
   End If
End Sub

What it should do is simply to mute the ringing for the default telephony app and then un-mute it if it intercepts the ringing status.

Now, everything in service create works as expected, so when calling my device I get the default telephony app to come to foreground, shows an incoming call along with the callig number BUT silenced.
What doesn't work is that the PhoneStatusChanged event is never called so the service can take no action on it.

Correct me if I am wrong, but using PhoneEvents in a service along with Service.StartForeround is an alternative to have an intent filter in the manifest (dynamic vs. static); the benefit of using this approach should be that I can start/stop the service at will comanding when the interception of broadcasts should go on on/off.

Do you think there's the possibility that my device's default telephony app runs the same RINGING interceptor to a very high priority so to be the first to receive it and then one "consuming" it, so nothing is left to my service? If yes, how can I discover it and how can I circumvent it?

Umberto
 

bsnqt

Active Member
Licensed User
Longtime User
I think you can use PhoneStateListener.
Then You can change from:
If State ="RINGING"...
to test with this:
If State = 1 (for Ringing) or State = 0 (Idle)
It will fire.
Note that the State's value is Integer not string. So the sub will look like:

B4X:
PSL_onCallStateChanged (State As Int, caller As String)
If Status = 1 then

End If
End Sub
 
Last edited:
Upvote 0

udg

Expert
Licensed User
Longtime User
@bsnqt: thank you for your hint.

I solved my problem following a similar approach to Erel's thread about static vs. dynamic intent filters.
So, now my manifest looks like
B4X:
AddManifestText(
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/>
<supports-screens android:largeScreens="true"
  android:normalScreens="true"
  android:smallScreens="true"
  android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.
AddPermission(android.permission.READ_PHONE_STATE)
AddReceiverText(svc_dnd2,
<intent-filter>
  <action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>)
where the added settings are appended after the comment "End of default text".

And my service relevant code is:
B4X:
Sub Process_Globals
   Dim p As Phone
   Dim Intercept As Boolean  'set in main to allow/disallow service operation
   Dim caller As String
   Dim AllowedC As List       'white list of callers
End Sub

Sub Service_Start (StartingIntent As Intent)
  If (Intercept = True) AND (StartingIntent.Action = "android.intent.action.PHONE_STATE") Then
    'nute the speakers on ringing
    p.SetMute(p.VOLUME_RING,True)
    If StartingIntent.HasExtra("state") Then
      If StartingIntent.GetExtra("state") = "RINGING" Then
        caller = StartingIntent.GetExtra("incoming_number")
        Dim ring As Boolean
        ring = Accept(caller)
        If ring Then
          'un-mute speakers for selected callers
          p.SetMute(p.VOLUME_RING,False)
        Else
          'play wav or any other neededaction
        End If
      End If 
    End If   
  End If 
End Sub

I guess that both Intercept and AllowedC need to be initialized reading a saved-options file, since the service could now be called even if the main app never loaded from current phone session start (it's cold start).

Umberto
 
Upvote 0

bsnqt

Active Member
Licensed User
Longtime User
@udg: Great! Nice to hear you solved your problem.

Please note that for some cases if you mute the ringer at the beginning (when receiving the intent, as shown in your code), later it may be too late to unmute it, if your caller's identification process is too long (the call ringer will stay mute, even you set it back to false
p.SetMute(p.VOLUME_RING,False)). It is something very similar to the natural user's behaviour (for example, you receive a call and decide to mute it using a hard button, then later - still during the call rings - you cannot unmute the ringer back).
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi bsnqt,
thank you for your hint. My "Accept" function should complete very fast since it's essentially a lookup in a short "white" list of authorized numbers.
Anyway, I am finalizing the BETA version of my app and, as soon I am ready, I'll publish a link on this great NG so to have some feedback from volunteers and anyone interested.

Umberto
 
Upvote 0
Top