Android 8.0 Oreo로 업데이트
이 질문은 원래 Android L 지원에 대한 질문 이었지만 사람들은 여전히이 질문과 답변에 답하는 것처럼 보이므로 Android 8.0 Oreo에 도입 된 개선 사항을 설명 할 가치가 있습니다. 이전 버전과 호환되는 방법은 아래에 계속 설명되어 있습니다.
무엇이 바뀌 었습니까?
을 시작으로 안드로이드 8.0 오레오 의 전화 권한 그룹은 또한 포함 ANSWER_PHONE_CALLS의 권한을 . 권한의 이름에서 알 수 있듯이이 권한을 유지하면 리플렉션을 사용하거나 사용자를 시뮬레이션하지 않고도 적절한 API 호출을 통해 앱이 프로그래밍 방식으로 수신 호출을 수락 할 수 있습니다.
이 변경 사항을 어떻게 활용합니까?
이전 Android 버전을 지원하는 경우 런타임시 시스템 버전을 확인 해야 이전 Android 버전에 대한 지원을 유지하면서이 새로운 API 호출을 캡슐화 할 수 있습니다. 최신 Android 버전의 표준과 같이 런타임 중에 새 권한을 얻으려면 런타임에 요청 권한을 따라야 합니다.
권한을 얻은 후 앱은 TelecomManager의 acceptRingingCall 메소드 를 호출하기 만하면 됩니다. 기본 호출은 다음과 같습니다.
TelecomManager tm = (TelecomManager) mContext
.getSystemService(Context.TELECOM_SERVICE);
if (tm == null) {
throw new NullPointerException("tm == null");
}
tm.acceptRingingCall();
방법 1 : TelephonyManager.answerRingingCall ()
장치를 무제한으로 제어 할 수있는 경우.
이게 뭐야?
숨겨진 내부 메서드 인 TelephonyManager.answerRingingCall ()이 있습니다. 인터 웹에서 논의 된 ITelephony.answerRingingCall ()의 다리 역할을하며 처음에는 유망 해 보입니다. 그것은이다 없습니다 볼 수 4.4.2_r1 이 단지에서 커밋 도입으로 83da75d를 안드로이드 4.4 킷캣 ( 4.4.3_r1에 선 1537을 커밋에) 이상 "재 도입" f1e1e77 롤리팝 (대한 5.0.0_r1에 라인 3138 )에 의한 방법에 힘내 트리가 구조화되었습니다. 즉, Lollipop으로 만 장치를 지원하지 않는 한, 현재로서는 시장 점유율이 적다는 사실을 고려할 때 잘못된 결정일 수 있지만이 경로를 따라가는 경우에도 대체 방법을 제공해야합니다.
이것을 어떻게 사용할까요?
문제의 메서드는 SDK 응용 프로그램 사용에서 숨겨져 있으므로 런타임 중에 메서드를 동적으로 검사하고 사용 하려면 리플렉션 을 사용해야합니다. 반성에 익숙하지 않은 경우 반성 이란 무엇이며 왜 유용합니까?를 빨리 읽을 수 있습니다 . . 관심이있는 경우 Trail : The Reflection API 에서 세부 사항을 자세히 알아볼 수도 있습니다 .
코드에서는 어떻게 보입니까?
final String LOG_TAG = "TelephonyAnswer";
TelephonyManager tm = (TelephonyManager) mContext
.getSystemService(Context.TELEPHONY_SERVICE);
try {
if (tm == null) {
throw new NullPointerException("tm == null");
}
tm.getClass().getMethod("answerRingingCall").invoke(tm);
} catch (Exception e) {
Log.e(LOG_TAG, "Unable to use the Telephony Manager directly.", e);
}
이것은 사실이 되기에는 너무 좋습니다!
사실 약간의 문제가 하나 있습니다. 이 메소드는 완전히 작동해야하지만 보안 관리자는 호출자가 android.permission.MODIFY_PHONE_STATE 를 보유하기를 원합니다 . 이 권한은 제 3자가 시스템을 건드리지 않을 것으로 예상되기 때문에 시스템의 부분적으로 문서화 된 기능의 영역에 있습니다 (문서에서 볼 수 있듯이). 를 추가해 볼 수는 <uses-permission>
있지만이 권한의 보호 수준이 signature | system 이기 때문에 좋지 않습니다 ( 5.0.0_r1의 core / AndroidManifest 1201 줄 참조 ).
당신이 읽을 수있는 문제 34785을 : 업데이트는 안드로이드 : protectionLevel 문서 2012 년에 다시 만들어진 우리는 "파이프 구문"특정에 대한 세부 사항을 누락 있는지,하지만 주위 실험에서, 모든 의미 그것이 역할을한다 표시 'AND' 권한이 부여 되려면 지정된 플래그가 충족되어야합니다. 이러한 가정하에 작업하면 애플리케이션이 있어야합니다.
시스템 애플리케이션으로 설치됩니다.
이는 문제가 없으며 아직 패키지화되지 않은 맞춤 ROM에 Google 앱을 루팅하거나 설치할 때와 같이 복구시 ZIP을 사용하여 설치하도록 사용자에게 요청하여 수행 할 수 있습니다.
프레임 워크 /베이스 (일명 ROM)와 동일한 서명으로 서명됩니다.
여기에서 문제가 발생합니다. 이렇게하려면 프레임 워크 /베이스에 서명하는 데 사용되는 키를 손에 넣어야합니다. Nexus 공장 이미지에 대한 Google의 키에 액세스해야 할뿐만 아니라 다른 모든 OEM 및 ROM 개발자의 키에도 액세스해야합니다. 이것은 그럴듯 해 보이지 않으므로 사용자 정의 ROM을 만들고 사용자에게 전환하도록 요청하거나 (어려울 수 있음) 권한 보호 수준을 우회 할 수있는 익스플로잇을 찾아 시스템 키로 애플리케이션에 서명 할 수 있습니다. (어려울 수도 있습니다).
또한이 동작은 문제 34792 와 관련된 것으로 보입니다. Android Jelly Bean / 4.1 : android.permission.READ_LOGS는 더 이상 문서화되지 않은 개발 플래그와 함께 동일한 보호 수준을 활용하는 작동하지 않습니다 .
TelephonyManager로 작업하는 것은 좋게 들리지만 실제로는 쉽지 않은 적절한 권한을 얻지 않으면 작동하지 않습니다.
다른 방법으로 TelephonyManager를 사용하는 것은 어떻습니까?
안타깝게도 멋진 도구를 사용 하려면 android.permission.MODIFY_PHONE_STATE 를 보유해야하므로 해당 메소드에 액세스하는 데 어려움을 겪게됩니다.
방법 2 : 서비스 콜 서비스 코드
기기에서 실행중인 빌드가 지정된 코드로 작동하는지 테스트 할 수있는 경우.
TelephonyManager와 상호 작용할 수 없으면 service
실행 파일을 통해 서비스와 상호 작용할 수도 있습니다 .
어떻게 작동합니까?
매우 간단하지만이 경로에 대한 문서는 다른 것보다 훨씬 적습니다. 우리는 실행 파일이 서비스 이름과 코드라는 두 가지 인수를받습니다.
서비스 이름 우리가 사용하려는입니다 전화 .
이것은를 실행하여 볼 수 있습니다 service list
.
코드 우리가 사용하고자는 것처럼 보인다 (6) 하지만 지금은 것 같다 5 .
이를 기반으로 된 것 같습니다 IBinder.FIRST_CALL_TRANSACTION 지금은 많은 버전 + 5 (에서 1.5_r4 에 4.4.4_r1 )하지만 현지 테스트하는 동안 코드 5 걸려 오는 전화에 응답했다. Lollipo는 전체적으로 대규모 업데이트이므로 여기에서도 내부가 변경된 것은 이해할 수 있습니다.
이 결과는 service call phone 5
.
이를 프로그래밍 방식으로 어떻게 활용합니까?
자바
다음 코드는 개념 증명으로 작동하도록 만들어진 대략적인 구현입니다. 당신이 실제로 가서이 방법을 사용하려면, 당신은 아마 체크 아웃 할 문제가없는 스와 사용에 대한 가이드 라인을 가능성이 더 완벽하게 개발로 전환 libsuperuser 에 의해 Chainfire .
try {
Process proc = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(proc.getOutputStream());
os.writeBytes("service call phone 5\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
if (proc.waitFor() == 255) {
}
} catch (IOException e) {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
명백한
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
정말 루트 액세스가 필요합니까?
슬프게도 그렇게 보인다. Runtime.exec 를 사용해 볼 수 는 있지만 그 경로로 운이 좋지 않았습니다.
이것은 얼마나 안정적인가요?
물어봐서 기뻐요. 문서화되지 않았기 때문에 위의 코드 차이에서 알 수 있듯이 다양한 버전으로 나눌 수 있습니다. 서비스 이름은 다양한 빌드에서 전화로 유지되어야 하지만, 우리가 아는 한 코드 값은 동일한 버전의 여러 빌드 (예 : OEM 스킨에 의한 내부 수정)에서 변경 될 수 있으며 사용 된 방법을 깨뜨릴 수 있습니다. 따라서 테스트가 Nexus 4 (mako / occam)에서 수행되었음을 언급 할 가치가 있습니다. 개인적으로이 방법을 사용하지 말라고 조언하지만 더 안정적인 방법을 찾을 수 없기 때문에 이것이 최선이라고 생각합니다.
원래 방법 : 헤드셋 키 코드 의도
정착해야 할 때를 위해.
다음 섹션은 Riley C 의이 답변 에 크게 영향을 받았습니다 .
원래 질문에 게시 된 시뮬레이션 된 헤드셋 의도 방법은 예상대로 방송되는 것처럼 보이지만 전화 응답 목표를 달성하지 못하는 것 같습니다. 이러한 인 텐트를 처리해야하는 코드가있는 것처럼 보이지만 단순히 신경 쓰지 않고 있으므로이 방법에 대한 새로운 대응책이 있어야합니다. 로그에도 관심있는 내용이 표시되지 않으며 저는 개인적으로 Android 소스를 파헤치는 것이 Google이 어쨌든 사용 된 방법을 쉽게 깨뜨리는 약간의 변경을 도입 할 가능성이 있기 때문에 가치가 있다고 생각하지 않습니다.
지금 당장 할 수있는 일이 있습니까?
입력 실행 파일을 사용하여 동작을 일관되게 재현 할 수 있습니다. KeyEvent.KEYCODE_HEADSETHOOK 에서 간단히 전달하는 키 코드 인수를받습니다 . 이 방법은 루트 액세스가 필요하지 않아 일반 대중의 일반적인 사용 사례에 적합하지만 방법에는 작은 단점이 있습니다. 헤드셋 버튼 누르기 이벤트는 권한을 요구하도록 지정할 수 없으므로 실제처럼 작동합니다. 버튼을 누르고 전체 체인을 통해 거품이 발생합니다. 즉, 우선 순위가 더 높은 다른 사람이 처리 할 준비가되지 않은 경우 음악 플레이어가 재생을 시작하도록 트리거 할 수 있으므로 버튼 누르기를 시뮬레이션 할시기에 대해주의해야합니다. 이벤트.
암호?
new Thread(new Runnable() {
@Override
public void run() {
try {
Runtime.getRuntime().exec("input keyevent " +
Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
} catch (IOException e) {
String enforcedPerm = "android.permission.CALL_PRIVILEGED";
Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_HEADSETHOOK));
Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_HEADSETHOOK));
mContext.sendOrderedBroadcast(btnDown, enforcedPerm);
mContext.sendOrderedBroadcast(btnUp, enforcedPerm);
}
}
}).start();
tl; dr
Android 8.0 Oreo 이상을위한 멋진 공용 API가 있습니다.
Android 8.0 Oreo 이전에는 공개 API가 없습니다. 내부 API는 제한이 없거나 단순히 문서가 없습니다. 주의해서 진행해야합니다.