Broadcast Receiver
Broadcast Receiver to komponent systemu Android, który nasłuchuje zdarzenia systemowe lub aplikacyjne. Takim zdarzeniem może być np. informacja o nowej wiadomości SMS, połączeniu przychodzącym lub wychodzącym, czy niskim stanie baterii.
Za pomocą odbiornika nadawczego pokażę jak wykryć przychodzące połączenie telefoniczne w aplikacji na Androida.
Create Broadcast Receiver
Istnieją dwa sposoby na zarejestrowanie i utworzenie odbiornika transmisji.
Pierwszy sposób to rejestracja w kodzie aplikacji.
class MainActivity : AppCompatActivity() { private val filter = IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED) private val broadcast = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onResume() { super.onResume() registerReceiver(broadcast, filter) } override fun onPause() { super.onPause() unregisterReceiver(broadcast) } }
Rejestracja w kodzie aplikacji oznacza, że nasza aplikacja nasłuchuje tylko wtedy, gdy jest aktywna.
W drugim sposobie nasz BroadcastReceiver zostanie uruchomiony nawet wtedy, gdy aplikacja jest aktualnie nieaktywna, czyli słuchamy bez przerwy. Do wykrywania połączeń przychodzących lepszym wyborem będzie opcja poniżej.
Utwórz nową klasę rozszerzającą klasę BroadcastReceiver i zaimplementuj metodę onReceive().
class CallReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, p1: Intent?) { } }
Następnie należy zarejestrować odbiornik transmisji w pliku AndroidManifest.xml.
<receiver android:name=".CallReceiver" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> </receiver>
Uprawnienia
Nadaj uprawnienia do odczytu stanu telefonu i odczytu rejestru połączeń w pliku AndroidManifest.xml.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.READ_CALL_LOG"/>
Odczyt State Listener
W metodzie onReceive wytworzyć PhoneStateListener.
class CallReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, p1: Intent?) { val telephonyManager: TelephonyManager = context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager; telephonyManager.listen(object: PhoneStateListener(){ override fun onCallStateChanged(state: Int, phoneNumber: String?) { super.onCallStateChanged(state, phoneNumber) } }, PhoneStateListener.LISTEN_CALL_STATE); } }
Kiedy przychodzi nowe wywołanie wywoływana jest metoda onCallStateChanged.
Poniżej jest wyjaśnione co oznaczają parametry metody onCallStateChanged.
CALL_STATE_IDLE – brak aktywności
CALL_STATE_RINGING – Dzwonek. Nadeszło nowe połączenie i dzwoni lub oczekuje. W tym drugim przypadku inne połączenie jest już aktywne.
CALL_STATE_OFFHOOK – Off-hook. Istnieje przynajmniej jedno połączenie, które jest wybierane, aktywne lub zawieszone, a żadne połączenie nie dzwoni ani nie oczekuje.
class CallReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, p1: Intent?) { val telephonyManager: TelephonyManager = context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager; telephonyManager.listen(object: PhoneStateListener(){ override fun onCallStateChanged(state: Int, phoneNumber: String?) { super.onCallStateChanged(state, phoneNumber) when (state) { TelephonyManager.CALL_STATE_IDLE -> { Log.i(TAG,"not in call") } TelephonyManager.CALL_STATE_RINGING -> { Log.i(TAG, "ringing") } TelephonyManager.CALL_STATE_OFFHOOK -> { Log.i(TAG, "call is dialing, active or on hold") } } } }, PhoneStateListener.LISTEN_CALL_STATE); } }
Jak zmienia się stan przy połączeniu przychodzącym?
Kiedy dzwoni, przechodzi ze stanu IDLE do RINGING. Następnie gdy zostanie odebrane zmienia się na OFFHOOK, na IDLE gdy się rozłączy. Aby zarejestrować zmiany, trzeba stworzyć dodatkowe zmienne.
class ServiceReceiver : BroadcastReceiver() { var laststate: Int = 0 var isIncoming: Boolean = false override fun onReceive(context: Context?, p1: Intent?) { val telephonyManager: TelephonyManager = context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager; telephonyManager.listen(object: PhoneStateListener(){ override fun onCallStateChanged(state: Int, phoneNumber: String?) { super.onCallStateChanged(state, phoneNumber) if (state == TelephonyManager.CALL_STATE_RINGING) { isIncoming = true } if (state == TelephonyManager.CALL_STATE_OFFHOOK && laststate != TelephonyManager.CALL_STATE_RINGING) { isIncoming = false } if (state == TelephonyManager.CALL_STATE_IDLE && laststate == TelephonyManager.CALL_STATE_OFFHOOK) { Log.i(TAG, "incoming call end, phone number: $phoneNumber") } laststate = state } }, PhoneStateListener.LISTEN_CALL_STATE); } }
Na połączeniach wychodzących stany zmieniają się inaczej. Przechodzi z IDLE do OFFHOOK, gdy wybierze numer, do IDLE, gdy się rozłączy. Więc połączenia wychodzące mogą być wykrywane w podobny sposób.