Programação para a Plataforma Android – Aula 17 Broadcasts • O que são eventos de difusão? • Como capturar eventos de chamadas telefônicas? • Como verificar o estado da bateria? • Como implementar receptores de eventos de difusão? • O que são intenções assíncronas? • O que são intenções pendentes? Intenções de Difusão • Intenções de Broadcast são entregues para todos os receptores de broadcast registrados no disposiGvo Android. – Por exemplo, quando uma chamada é recebida, todos os receptores desse Gpo de evento serão acordados para tratá‐lo. Qual a diferenç a entre receptore s de broadcast e provedores de serviço? Exemplos de Broadcast • ACTION_BATTERY_LOW: um aviso que a bateria está quase descarregada. • ACTION_HEADSET_PLUG: um fone de ouvido foi conectado (ou desconectado). • ACTION_SCREEN_ON: a tela foi ligada. • ACTION_TIMEZONE_CHANGED: o aparelho passou de um fuso para outro. Recebendo Chamadas • Chamadas telefônicas são capturadas como eventos de difusão (broadcast). Lendo números: Escreva uma aplicação que leia o número recebido em uma chamada, e o imprima na tela de log. MyPhoneReceiver public class MyPhoneReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { String state = extras.getString(TelephonyManager.EXTRA_STATE); Log.w("DEBUG", state); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { String phoneNumber = extras .getString(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.w("DEBUG", phoneNumber); } } } } MyPhoneReceiver.java Broadcast Receivers não são aGvidades • Para usarmos nosso receptor, precisamos implementar uma aGvidade. – Toda aplicação possui uma aGvidade. a Existe algum o relação entre receptor de intenções, e e? essa atividad public class MainAcGvity extends AcGvity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Como "lig amos" setContentView(R.layout.acGvity_main); o recepto r de } eventos de } difusã MainAcGvity.java o? O Manifesto <applicaGon AndroidManifest.xml android:icon="@drawable/ic_launcher" android:label="@string/app_name" Como simular a android:theme="@style/AppTheme" > recepção de <acGvity uma chamada? android:name=".MainAcGvity" android:label="@string/Gtle_acGvity_main" > <intent‐filter> <acGon android:name="android.intent.acGon.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent‐filter> </acGvity> <receiver android:name=".MyPhoneReceiver" > <intent‐filter> <ac=on android:name="android.intent.ac=on.PHONE_STATE" > </ac=on> </intent‐filter> </receiver> </applicaGon> <uses‐permission android:name="android.permission.READ_PHONE_STATE" /> Controle de Emulação • O plugin Android para Eclipse provê uma interface para a emissão de sinais ao emulador. Estados de uma Chamada public class MyPhoneReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { String state = extras.getString(TelephonyManager.EXTRA_STATE); Log.w("DEBUG", state); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { String phoneNumber = extras .getString(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.w("DEBUG", phoneNumber); } } } } Encontrando seu Número public class MainAcGvity extends AcGvity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); String phonenumber = tm.getLine1Number(); Log.v("Phone_data", phonenumber == null ? "No number" : phonenumber); } } MainAcGvity.java Encontrando Informações de Operador MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); String phonenumber = tm.getLine1Number(); Log.v("Phone_data", phonenumber); String operatorname = tm.getNetworkOperatorName(); Log.v("Phone_data", operatorname); String operatorcode = tm.getNetworkOperator(); Log.v("Phone_data", operatorcode); String operatoriso = tm.getNetworkCountryIso(); Log.v("Phone_data", operatoriso); } Disparando Eventos de Difusão • Além de receber intenções de difusão, o usuário pode também disparar esse Gpo de intenção. • URIs são usados para qualificar essas intenções. Difundindo eventos: Defina um evento de difusão "br.com.dcc052. aula17" e implemente um receptor que o capture. Registrando a Intenção no Manifesto <applicaGon android:icon="@drawable/ic_launcher" Para que serve android:label="@string/app_name" essa declaração? android:theme="@style/AppTheme" > <acGvity android:name=".MainAcGvity" O que é android:label="@string/Gtle_acGvity_main" > esse <intent‐filter> nome? <acGon android:name="android.intent.acGon.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent‐filter> </acGvity> Como uma <receiver android:name=".MyBroadcastReceiver" > intenção do <intent‐filter> tipo "br.com. <ac=on android:name="br.com.dcc052.aula17" /> dcc052.aula17" </intent‐filter> Poderia ser </receiver> disparada? </applicaGon> AndroidManifest.xml Difundindo uma Intenção MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); Intent intent = new Intent(); intent.setAc=on("br.com.dcc052.aula17"); sendBroadcast(intent); } O que está faltando implementar? Definindo um Receptor MyBroadcastReceiver.java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.v("MyReceiver", intent.toString()); } } O que deverá ser impresso? Definindo um Receptor MyBroadcastReceiver.java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.v("MyReceiver", intent.toString()); Como pa } ssa r dados pa ra o receptor ? } MyReceiver1 Intent { act=br.com.dcc052.aula17 flg=0x10 cmp=com.dcc052.aula17/.MyBroadcastReceiver (has extras) } Comunicando Dados MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); Será que é possível Intent intent = new Intent(); termos mais de um intent.setAcGon("br.com.dcc052.aula17"); receptor para a intent.putExtra("Arg1", "Oi"); mesma intenção sendBroadcast(intent); difundida? } MyBroadcastReceiver.java @Override public void onReceive(Context context, Intent intent) { String arg = intent.getStringExtra("Arg1"); Log.v("MyReceiver0", arg); } MúlGplos Receptores • Podemos registrar vários receptores para uma mesma intenção difundida. • Cada receptor deve ser registrado no manifesto da aplicação. AndroidManifest.xml <receiver android:name=".MyBroadcastReceiver0" > <intent‐filter> <acGon android:name="br.com.dcc052.aula17" /> O que mais </intent‐filter> precisa ser </receiver> implementado? <receiver android:name=".MyBroadcastReceiver1" > <intent‐filter> <acGon android:name="br.com.dcc052.aula17" /> </intent‐filter> </receiver> MúlGplos Receptores public class MyBroadcastReceiver1 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.v("Receiver1", intent.toString()); } } MyBroadcastReceiver0.java MyBroadcastReceiver1.java public class MyBroadcastReceiver0 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String arg = intent.getStringExtra("Arg1"); Log.v("Receiver0", arg); } } Intenções Assíncronas • Algumas intenções, chamadas assíncronas (s3cky) não desaparecem tão logo são lançadas. • É possível consultar a úlGma instância de uma intenção desse Gpo. • Os eventos de bateria são anunciados via intenções assíncronas. Escreva uma atividade que determine o estado da bateria do dispositivo. Lendo o Estado da Bateria MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent baveryStatus = this.registerReceiver(null, filter); int status = baveryStatus.getIntExtra(BaveryManager.EXTRA_STATUS, ‐1); boolean isCharging = status == BaveryManager.BATTERY_STATUS_CHARGING; Log.v("Bavery", "Estah carregando? " + isCharging); boolean isFull = status == BaveryManager.BATTERY_STATUS_FULL; Log.v("Bavery", "Estah carregado? " + isFull); int chargePlug = baveryStatus.getIntExtra(BaveryManager.EXTRA_PLUGGED, ‐1); boolean usbCharge = chargePlug == BaveryManager.BATTERY_PLUGGED_USB; Log.v("Bavery", "Estah carregando via USB? " + usbCharge); boolean acCharge = chargePlug == BaveryManager.BATTERY_PLUGGED_AC; Log.v("Bavery", "Estah carregando via tomada? " + acCharge); } Lendo o Estado da Bateria MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent baveryStatus = this.registerReceiver(null, filter); int status = baveryStatus.getIntExtra(BaveryManager.EXTRA_STATUS, ‐1); boolean isCharging = status == BaveryManager.BATTERY_STATUS_CHARGING; Qual argumento E porque estamos Log.v("Bavery", "Estah carregando? " + isCharging); é esperado passando o objeto boolean isFull = status == BaveryManager.BATTERY_STATUS_FULL; nessa posição? nulo aqui? Log.v("Bavery", "Estah carregado? " + isFull); int chargePlug = baveryStatus.getIntExtra(BaveryManager.EXTRA_PLUGGED, ‐1); boolean usbCharge = chargePlug == BaveryManager.BATTERY_PLUGGED_USB; Log.v("Bavery", "Estah carregando via USB? " + usbCharge); boolean acCharge = chargePlug == BaveryManager.BATTERY_PLUGGED_AC; Log.v("Bavery", "Estah carregando via tomada? " + acCharge); } Lendo o Estado da Bateria MainAcGvity.java @Override public void onCreate(Bundle savedInstanceState) { Como saber a super.onCreate(savedInstanceState); Que informações quantidade de setContentView(R.layout.acGvity_main); serão energia que resta IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); impressas? na bateria? Intent baveryStatus = this.registerReceiver(null, filter); int status = baveryStatus.getIntExtra(BaveryManager.EXTRA_STATUS, ‐1); boolean isCharging = status == Ba\eryManager.BATTERY_STATUS_CHARGING; Log.v("Ba\ery", "Estah carregando? " + isCharging); boolean isFull = status == Ba\eryManager.BATTERY_STATUS_FULL; Log.v("Ba\ery", "Estah carregado? " + isFull); int chargePlug = ba\eryStatus.getIntExtra(Ba\eryManager.EXTRA_PLUGGED, ‐1); boolean usbCharge = chargePlug == Ba\eryManager.BATTERY_PLUGGED_USB; Log.v("Ba\ery", "Estah carregando via USB? " + usbCharge); boolean acCharge = chargePlug == Ba\eryManager.BATTERY_PLUGGED_AC; Log.v("Ba\ery", "Estah carregando via tomada? " + acCharge); } Energia Restante MainAcGvity.java @Override Explique public void onCreate(Bundle savedInstanceState) { essa conta… super.onCreate(savedInstanceState); setContentView(R.layout.acGvity_main); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent baveryStatus = this.registerReceiver(null, filter); ... int level = ba\eryStatus.getIntExtra(Ba\eryManager.EXTRA_LEVEL, ‐1); int scale = ba\eryStatus.getIntExtra(Ba\eryManager.EXTRA_SCALE, ‐1); float ba\eryPct = level / (float) scale; Log.v("Ba\ery", "Level = " + ba\eryPct); } Intenções Pendentes • É possível programar intenções para acontecer em algum momento no futuro. – Esse Gpo de intenção chama‐ se intenção pendente. • Existe um controlador de eventos futuros, AlarmManager, que pode ser usado para disparar intenções pendentes. Definindo um alarme: Crie uma atividade que leia uma quantidade de segundos X, e programe uma intenção para X segundos no futuro. alarm.xml Definindo um Layout <?xml version="1.0" encoding="u<‐8"?> <LinearLayout xmlns:android="hBp://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientaGon="ver3cal" > <EditText android:id="@+id/3me" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:focusable="true" android:inputType="numberDecimal" > </EditText> <Buvon android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="startAlert" android:text="@string/alarm_buBon_label" > </Buvon> </LinearLayout> Precisamos definir um receptor para a intenção futura. Recebendo Intenções de Alarme MyAlarmReceiver.java O que esse código está buscando? public class MyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, context.getString(R.string.alarm_fired_message), Toast.LENGTH_LONG).show(); Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(2000); } Para que } serve essa classe? Para vibrar é preciso permissão. Permissão para Vibrar MyAlarmReceiver.java Como a intenção será disparada? public class MyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, context.getString(R.string.alarm_fired_message), Toast.LENGTH_LONG).show(); Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(2000); } } AndroidManifest.xml <uses‐permission android:name="android.permission.VIBRATE" /> … <receiver android:name=".MyAlarmReceiver" /> Criando uma Intenção Pendente public class AlarmAcGvity extends AcGvity { Grande mistério: @Override como/quando o public void onCreate(Bundle savedInstanceState) { método super.onCreate(savedInstanceState); startAlert é setContentView(R.layout.alarm); chamado? } public void startAlert(View view) { EditText text = (EditText) findViewById(R.id.Gme); int i = Integer.parseInt(text.getText().toString()); Intent intent = new Intent(this, MyAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicaGonContext(), 234324243, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent); Toast.makeText(this, i + getString(R.string.alarm_started_message), Lembra de Toast.LENGTH_LONG).show(); registrar a } intenção no } manifesto AlarmAcGvity.java Mais Manifesto <acGvity android:name=".AlarmAcGvity" android:label="@string/Gtle_acGvity_main" > <intent‐filter> <acGon android:name="android.intent.acGon.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent‐filter> </acGvity> AndroidManifest.xml Amarração entre XML e Java <Buvon android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="startAlert" android:text="@string/alarm_buvon_label" > </Buvon> Como se dá a amarração entre Java e XML nesse exemplo? alarm.xml AlarmAcGvity.java public class AlarmAcGvity extends AcGvity { @Override public void onCreate(Bundle savedInstanceState) {...} public void startAlert(View view) {...} } A Ordem dos Eventos public class AlarmAcGvity extends AcGvity { * O que acontecerá @Override tão logo o usuário public void onCreate(Bundle savedInstanceState) { clique no botão? super.onCreate(savedInstanceState); setContentView(R.layout.alarm); * Qual a ordem dos } eventos? public void startAlert(View view) { EditText text = (EditText) findViewById(R.id.Gme); int i = Integer.parseInt(text.getText().toString()); Intent intent = new Intent(this, MyAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicaGonContext(), 234324243, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent); Toast.makeText(this, i + getString(R.string.alarm_started_message), Toast.LENGTH_LONG).show(); } } AlarmAcGvity.java A Ordem dos Eventos public class AlarmAcGvity extends AcGvity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.alarm); } public void startAlert(View view) { EditText text = (EditText) findViewById(R.id.Gme); int i = Integer.parseInt(text.getText().toString()); Intent intent = new Intent(this, MyAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicaGonContext(), 234324243, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (i * 1000), pendingIntent); Toast.makeText(this, i + getString(R.string.alarm_started_message), Toast.LENGTH_LONG).show(); } } AlarmAcGvity.java strings.xml strings.xml <resources> <string name="app_name">Aula17</string> <string name="Gtle_acGvity_main">MainAcGvity</string> <string name="main_acGvity_label">AGvidade Principal</string> <string name="alarm_buvon_label">Iniciar</string> <string name="alarm_fired_message">Hora de acordar!</string> <string name="alarm_started_message"> segundos para alarme disparar.</string> </resources>