주요 체크포인트
- Permission 획득
- 외부 APP 연동
. 주소록 정보 가져오기
. 음성인식으로 텍스트 정보 채우기
. SMS 전송결과 Broadcast 를 이용하여 Intent
package com.example.ch4_contacts_sms; import android.Manifest; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract; import android.speech.RecognizerIntent; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.telephony.SmsManager; import android.telephony.TelephonyManager; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button sendButton; Button voiceButton; Button contactButton; EditText phoneEdit; EditText contentEdit; boolean contactPermission; boolean smsPermission; boolean phonePermission; private final int REQUEST_FOR_CONTACT = 10; private final int REQUEST_FOR_VOICE = 20; private final int REQUEST_FOR_PERMISSION = 200; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sendButton = (Button) findViewById(R.id.button_send); voiceButton = (Button) findViewById(R.id.button_voice); contactButton = (Button) findViewById(R.id.button_contacts); phoneEdit = (EditText) findViewById(R.id.edit_phone); contentEdit = (EditText) findViewById(R.id.edit_content); sendButton.setOnClickListener(this); voiceButton.setOnClickListener(this); contactButton.setOnClickListener(this); // api level 22까지는(5.1) manifest에 <uses-permission>으로 등록만 하면 실행되는 개발자 신고제 // 23(6.0) 부터는 개발자가 manifest에 아무리 등록했다고 하더라도 user가 환경설정에서 permission enable/disable 조절가능 // manifest에 등록했다고 끝이 아니라 코드에스 그 부분을 실행할 때 권한획득여부 체크 필수 contactPermission = smsPermission = phonePermission = false; if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)== PackageManager.PERMISSION_GRANTED){ contactPermission = true; } if(ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS)== PackageManager.PERMISSION_GRANTED){ smsPermission = true; } if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)== PackageManager.PERMISSION_GRANTED){ phonePermission = true; } // 만약 disable로 되어있는 상태라면 runtime error 유발 // user에게 toast로 알려주고 끝내도 되지만, 강제로 permission을 조정할 수는 없으니 // permission 허가를 요청하도록하자 // user가 permission 허가를 하기 위해선 다시 환경설정으로 가기는 불편하니까 // 내 app에서 dialog로 permission 조정하도록 system dialog로 제공하자 if(!contactPermission && !smsPermission && !phonePermission){ requestPermission(); } } private void requestPermission(){ // user에게 permission허용 dialog를 띄우는 역할 ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS, Manifest.permission.SEND_SMS, Manifest.permission.READ_PHONE_STATE }, REQUEST_FOR_PERMISSION); } // requestPermission함수를 이용해서 유저에게 permission 조정 dialog를 띄웠다고 하더라도 // 여전히 유저가 거부했을 수도 있다. // dialog를 띄웠다고 끝이 아니라 사후 추적해야 한다. // requestPermission 함수에 의한 dialog 작업이 끝나는 순간 자동 호출 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode == REQUEST_FOR_PERMISSION && grantResults.length>0){ if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ contactPermission = true; } if(grantResults[1] == PackageManager.PERMISSION_GRANTED){ smsPermission = true; } if(grantResults[2] == PackageManager.PERMISSION_GRANTED){ phonePermission = true; } } } public void onClick(View v) { if(v==contactButton){ if(contactPermission){ // 주소록의 목록화면을 띄운다. Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://com.android.contacts/data/phones")); // 결과를 돌려 받아야 한다. startActivityForResult(intent, REQUEST_FOR_CONTACT); }else{ requestPermission(); } }else if(v == voiceButton){ // 외부 app연동시 activity intent를 발생시키는데 // 그 intent에 의해 구동될 activity가 없을 수도 있다. // intent를 발생시키기 전에 반응할 component가 있는지 체크 해야 함. // PackageManager: app이 설치된 static(run time시 동작중이지 않은)정보 추출 // 폰에 설치된 전체 app 목록(app의 package명==app의구분자 획득 가능) // intent에 반응할 component 정보 // ActivityManager: PackageManger와 거의 쌍으로 등장하는 class // : 설치된 app이 runtime시에 살아서 움직이고 있는 정보 // 시스템에 동작중인 모든 process 목록 - pid 획득, 프로세스 kill // 시스템에 동작중인 service 목록 // 폰의 top을 차지하고 있는 activity 정보 PackageManager pm = getPackageManager(); List<ResolveInfo> activities = pm.queryIntentActivities( // ACTION_RECOGNIZE_SPEECH action코드에 반응하는 activity get new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); if(activities.size() > 0){ Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); // free form: 말하는것 고대로 text로 // web search: 말하는것 web search intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); // Dialog의 title 문자열 intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "본문을 말하세요"); // 원한다면 언어도 고정가능하고 지정하지 않으면 폰의 기본 로케일을 따름 startActivityForResult(intent, REQUEST_FOR_VOICE); }else{ Toast t = Toast.makeText(this, "음성인식을 지원하지 않는 폰", Toast.LENGTH_SHORT); t.show(); } }else if(v == sendButton){ if(smsPermission && phonePermission){ // 유저 폰 번호를 sms 발신자 번호로 세팅 TelephonyManager telephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); String myNumber = telephonyManager.getLine1Number(); // sent ack시 실행할 intent 의뢰 ==> PendingIntent Intent intent = new Intent("SENT_SMS_ACTION"); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); // sms 발송 SmsManager smsManager = SmsManager.getDefault(); smsManager.sendTextMessage( phoneEdit.getText().toString(), myNumber, contentEdit.getText().toString(), pendingIntent, null ); }else{ requestPermission(); } } } // startActivityForResult에 의한 요청이 되돌아 올때 자동 호출 // requestCode: intent를 발생시킨 곳에서 intent를 구분하기 위해서 지정하는 임의의 숫자 // ex) startActivityForResult(intent, 10); 에서 '10' // resultCode: intent에 의해 수행된 곳에서 결과를 되돌리기전에 상태를 표현하기 위한 값 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == REQUEST_FOR_CONTACT && resultCode == RESULT_OK) { // 주소록 목록에서 홍길동을 눌러 되돌아 왔다고 하더라도 // 홍길동의 전화번호가 넘어오지는 않는다. // 홍길동을 식별하기 위한 식별자 값만 넘어온다. // url 문자열로 url의 맨 마지막 단어가 식별자값이다. String id = Uri.parse(data.getDataString()).getLastPathSegment(); // id값을 조건으로 구체적으로 원하는 데이터를 요청 provider 이용 // select된 row의 집합객체 // cursor를 움직여서 row하나씩 선택하고 선택된 row의 column data 추출 Cursor cursor = getContentResolver().query( // provider 식별자 uri ContactsContract.Data.CONTENT_URI, // select column조건, 뽑고자 하는 데이터 new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, // select의 where조건 ContactsContract.Data._ID + '=' + id, // where쿼리문에 (?)이 있을경우에 들어갈 args null, // orderby 문자열 null ); // row 선택 cursor.moveToFirst(); // 어차피 해당 id를 갖는 1개의 연락처만 선택됨 // data추출 및 화면 출력 phoneEdit.setText(cursor.getString(0)); }else if(requestCode == REQUEST_FOR_VOICE && resultCode == RESULT_OK){ ArrayList<String> results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); contentEdit.setText(results.get(0)); } } // sms send후에 시스템에 넘어오는 sen ack시에 실행될 receiver BroadcastReceiver sentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context _context, Intent _intent) { String msg=""; switch (getResultCode()) { case Activity.RESULT_OK: // 전송 성공 처리; break; msg="sms 전송 성공"; break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: // 일반적인 실패 처리; break; msg="sms 전송 실패"; break; case SmsManager.RESULT_ERROR_RADIO_OFF: // 무선 꺼짐 처리; break; msg="무선 꺼짐"; break; case SmsManager.RESULT_ERROR_NULL_PDU: // PDU 실패 처리; break; msg="pdu 오류"; break; } Toast t = Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT); t.show(); } }; protected void onResume() { super.onResume(); registerReceiver(sentReceiver, new IntentFilter("SENT_SMS_ACTION")); }; @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); unregisterReceiver(sentReceiver); } }
댓글 없음:
댓글 쓰기