Während ich versuche, einen benutzerdefinierten Bildschirm für eingehende Anrufe zu erstellen, versuche ich, einen eingehenden Anruf programmgesteuert zu beantworten. Ich verwende den folgenden Code, aber er funktioniert nicht in Android 5.0.
// Simulate a press of the headset button to pick up the call
Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(buttonDown, "android.permission.CALL_PRIVILEGED");
// froyo and beyond trigger on buttonUp instead of buttonDown
Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
android
android-5.0-lollipop
phone-call
incoming-call
Außenseiter
quelle
quelle
Antworten:
Update mit Android 8.0 Oreo
Obwohl die Frage ursprünglich für die Unterstützung von Android L gestellt wurde, scheinen die Leute diese Frage und Antwort immer noch zu beantworten. Es lohnt sich daher, die in Android 8.0 Oreo eingeführten Verbesserungen zu beschreiben. Die abwärtskompatiblen Methoden werden nachstehend noch beschrieben.
Was hat sich geändert?
Beginnend mit Android 8.0 Oreo , die PHONE Berechtigungsgruppe enthält auch die ANSWER_PHONE_CALLS Erlaubnis . Wie der Name der Berechtigung andeutet, kann Ihre App eingehende Anrufe programmgesteuert über einen geeigneten API-Aufruf annehmen, ohne das System mithilfe von Reflektion oder Simulation des Benutzers zu hacken.
Wie nutzen wir diese Änderung?
Sie sollten die Systemversion zur Laufzeit überprüfen, wenn Sie ältere Android-Versionen unterstützen, damit Sie diesen neuen API-Aufruf kapseln und gleichzeitig die Unterstützung für diese älteren Android-Versionen beibehalten können. Sie sollten zur Laufzeit Berechtigungen anfordern , um diese neue Berechtigung zur Laufzeit zu erhalten, wie dies bei neueren Android-Versionen Standard ist.
Nachdem Sie die Berechtigung erhalten haben, muss Ihre App lediglich die acceptRingingCall- Methode des TelecomManager aufrufen . Ein grundlegender Aufruf sieht dann wie folgt aus:
Methode 1: TelephonyManager.answerRingingCall ()
Für den Fall, dass Sie uneingeschränkte Kontrolle über das Gerät haben.
Was ist das?
Es gibt TelephonyManager.answerRingingCall (), eine versteckte interne Methode. Es fungiert als Brücke für ITelephony.answerRingingCall (), das in den Interwebs diskutiert wurde und zu Beginn vielversprechend erscheint. Es ist unter 4.4.2_r1 nicht verfügbar, da es nur in Commit 83da75d für Android 4.4 KitKat ( Zeile 1537 in 4.4.3_r1 ) eingeführt und später in Commit f1e1e77 für Lollipop ( Zeile 3138 in 5.0.0_r1 ) "wieder eingeführt" wurde Git-Baum wurde strukturiert. Dies bedeutet, dass Sie, wenn Sie nicht nur Geräte mit Lollipop unterstützen, was aufgrund des geringen Marktanteils derzeit wahrscheinlich eine schlechte Entscheidung ist, immer noch Fallback-Methoden bereitstellen müssen, wenn Sie diesen Weg gehen.
Wie würden wir das nutzen?
Da die betreffende Methode vor der Verwendung durch SDK-Anwendungen verborgen ist, müssen Sie Reflection verwenden , um die Methode zur Laufzeit dynamisch zu untersuchen und zu verwenden. Wenn Sie mit Reflexion nicht vertraut sind, können Sie schnell lesen, was Reflexion ist und warum sie nützlich ist. . Sie können sich auch eingehender mit den Besonderheiten von Trail: The Reflection API befassen, wenn Sie daran interessiert sind.
Und wie sieht das im Code aus?
Das ist zu gut um wahr zu sein!
Eigentlich gibt es ein kleines Problem. Diese Methode sollte voll funktionsfähig sein, aber der Sicherheitsmanager möchte, dass Anrufer android.permission.MODIFY_PHONE_STATE halten . Diese Berechtigung gilt nur für teilweise dokumentierte Funktionen des Systems, da von Dritten nicht erwartet wird, dass sie diese berühren (wie Sie der Dokumentation entnehmen können). Sie können versuchen, ein
<uses-permission>
dafür hinzuzufügen , aber das nützt nichts, da die Schutzstufe für diese Berechtigung signatur | system ist ( siehe Zeile 1201 von core / AndroidManifest unter 5.0.0_r1 ).Sie können die Ausgabe 34785: Update android: ProtectionLevel-Dokumentation lesen, die bereits 2012 erstellt wurde, um festzustellen , dass uns Details zur spezifischen "Pipe-Syntax" fehlen. Beim Experimentieren scheint sie jedoch als "UND" zu funktionieren, was bedeutet, dass alle Die angegebenen Flags müssen erfüllt sein, damit die Erlaubnis erteilt werden kann. Wenn Sie unter dieser Annahme arbeiten, bedeutet dies, dass Sie Ihre Bewerbung haben müssen:
Als Systemanwendung installiert.
Dies sollte in Ordnung sein und kann erreicht werden, indem die Benutzer aufgefordert werden, bei der Wiederherstellung eine ZIP-Datei zu installieren, z. B. beim Rooten oder Installieren von Google Apps auf benutzerdefinierten ROMs, auf denen diese noch nicht gepackt sind.
Signiert mit der gleichen Signatur wie Frameworks / Base, auch bekannt als System, auch bekannt als ROM.
Hier tauchen die Probleme auf. Dazu müssen Sie die Schlüssel zum Signieren von Frameworks / Base in der Hand haben. Sie müssten nicht nur auf die Schlüssel von Google für Nexus-Factory-Images zugreifen, sondern auch auf alle Schlüssel anderer OEMs und ROM-Entwickler. Dies erscheint nicht plausibel, sodass Sie Ihre Anwendung mit den Systemschlüsseln signieren lassen können, indem Sie entweder ein benutzerdefiniertes ROM erstellen und Ihre Benutzer auffordern, zu diesem zu wechseln (was möglicherweise schwierig ist) oder indem Sie einen Exploit finden, mit dem die Berechtigungsschutzstufe umgangen werden kann (was auch schwierig sein könnte).
Darüber hinaus scheint dieses Verhalten mit Problem 34792: Android Jelly Bean / 4.1: android.permission.READ_LOGS in Zusammenhang zu stehen, das nicht mehr funktioniert und dieselbe Schutzstufe zusammen mit einem undokumentierten Entwicklungsflag verwendet.
Die Arbeit mit dem TelephonyManager klingt gut, funktioniert aber nur, wenn Sie die entsprechende Berechtigung erhalten, was in der Praxis nicht so einfach ist.
Was ist mit der Verwendung von TelephonyManager auf andere Weise?
Leider müssen Sie anscheinend die android.permission.MODIFY_PHONE_STATE gedrückt halten , um die coolen Tools verwenden zu können, was wiederum bedeutet, dass Sie Schwierigkeiten haben werden, auf diese Methoden zuzugreifen.
Methode 2: Serviceabruf SERVICE CODE
Wenn Sie testen können, ob der auf dem Gerät ausgeführte Build mit dem angegebenen Code funktioniert.
Ohne mit dem TelephonyManager interagieren zu können, besteht auch die Möglichkeit, über die
service
ausführbare Datei mit dem Dienst zu interagieren .Wie funktioniert das?
Es ist ziemlich einfach, aber es gibt noch weniger Dokumentation über diese Route als über andere. Wir wissen mit Sicherheit, dass die ausführbare Datei zwei Argumente enthält - den Dienstnamen und den Code.
Der Dienstname, den wir verwenden möchten, ist Telefon .
Dies kann durch Laufen gesehen werden
service list
.Der Code, den wir verwenden möchten, scheint 6 gewesen zu sein, scheint aber jetzt 5 zu sein .
Es sieht so aus, als ob es für viele Versionen (von 1.5_r4 bis 4.4.4_r1 ) auf IBinder.FIRST_CALL_TRANSACTION + 5 basiert , aber während lokaler Tests hat der Code 5 einen eingehenden Anruf beantwortet. Da es sich bei Lollipo um ein umfangreiches Update handelt, sind verständlicherweise auch hier die Interna geändert worden.
Dies ergibt sich mit einem Befehl von
service call phone 5
.Wie nutzen wir das programmatisch?
Java
Der folgende Code ist eine grobe Implementierung, die als Proof of Concept dient. Wenn Sie diese Methode tatsächlich verwenden möchten, sollten Sie sich wahrscheinlich die Richtlinien für eine problemlose Verwendung von su ansehen und möglicherweise zum vollständig entwickelten libsuperuser von Chainfire wechseln .
Manifest
Benötigt dies wirklich Root-Zugriff?
Leider scheint es so. Sie können versuchen, Runtime.exec darauf zu verwenden, aber ich konnte mit dieser Route kein Glück haben.
Wie stabil ist das?
Ich bin froh, dass du gefragt hast. Da dies nicht dokumentiert ist, kann es zu verschiedenen Versionen kommen, wie der scheinbare Codeunterschied oben zeigt. Der Dienstname sollte wahrscheinlich über verschiedene Builds hinweg telefonisch bleiben , aber nach allem, was wir wissen, kann sich der Codewert über mehrere Builds derselben Version hinweg ändern (interne Änderungen, z. B. durch den OEM-Skin), was wiederum die verwendete Methode verletzt. Erwähnenswert ist daher, dass die Tests an einem Nexus 4 (mako / occam) durchgeführt wurden. Ich würde Ihnen persönlich davon abraten, diese Methode anzuwenden, aber da ich keine stabilere Methode finden kann, glaube ich, dass dies der beste Schuss ist.
Ursprüngliche Methode: Absichten des Headset-Schlüsselcodes
Für Zeiten, in denen Sie sich niederlassen müssen.
Der folgende Abschnitt wurde stark von dieser Antwort von Riley C beeinflusst .
Die in der ursprünglichen Frage angegebene simulierte Headset-Intent-Methode scheint wie erwartet gesendet zu werden, scheint jedoch das Ziel der Beantwortung des Anrufs nicht zu erreichen. Es scheint zwar Code zu geben, der diese Absichten handhaben sollte, aber sie werden einfach nicht beachtet, was bedeuten muss, dass gegen diese Methode neue Gegenmaßnahmen ergriffen werden müssen. Das Protokoll zeigt auch nichts Interessantes und ich persönlich glaube nicht, dass es sich lohnen wird, die Android-Quelle zu durchsuchen, nur weil Google möglicherweise eine geringfügige Änderung einführt, die die ohnehin verwendete Methode leicht bricht.
Können wir jetzt etwas tun?
Das Verhalten kann mithilfe der ausführbaren Eingabedatei konsistent reproduziert werden. Es nimmt ein Schlüsselcode-Argument auf, für das wir einfach KeyEvent.KEYCODE_HEADSETHOOK übergeben . Die Methode erfordert nicht einmal Root-Zugriff, sodass sie für allgemeine Anwendungsfälle in der Öffentlichkeit geeignet ist. Die Methode weist jedoch einen kleinen Nachteil auf: Das Ereignis zum Drücken der Headset-Taste kann nicht so angegeben werden, dass eine Berechtigung erforderlich ist, was bedeutet, dass es wie ein echtes Ereignis funktioniert Tastendruck und sprudelt durch die gesamte Kette, was wiederum bedeutet, dass Sie vorsichtig sein müssen, wann der Tastendruck simuliert werden soll, da dies beispielsweise den Musikplayer dazu veranlassen könnte, die Wiedergabe zu starten, wenn niemand anderes mit höherer Priorität bereit ist, damit umzugehen das Ereignis.
Code?
tl; dr
Es gibt eine schöne öffentliche API für Android 8.0 Oreo und höher.
Vor Android 8.0 Oreo gibt es keine öffentliche API. Die internen APIs sind tabu oder einfach ohne Dokumentation. Sie sollten mit Vorsicht vorgehen.
quelle
Die voll funktionsfähige Lösung basiert auf @ Walter Strods-Code.
Damit es funktioniert, müssen Sie eine (unsichtbare) Aktivität auf dem Sperrbildschirm anzeigen, auf dem der Code ausgeführt wird.
AndroidManifest.xml
Rufen Sie Accept Activity an
Stil
Nennen Sie endlich die Magie!
quelle
Das Folgende ist ein alternativer Ansatz, der für mich funktioniert hat. Das Schlüsselereignis wird direkt über die MediaController-API an den Telekommunikationsserver gesendet. Dies erfordert , dass die App hat BIND_NOTIFICATION_LISTENER_SERVICE Erlaubnis und wird ausdrücklich Erteilung Mitteilung Zugriff vom Benutzer gegeben:
NotificationReceiverService.class
im obigen Code könnte nur eine leere Klasse sein.Mit dem entsprechenden Abschnitt im Manifest:
Da das Ziel des Ereignisses explizit ist, sollte dies wahrscheinlich jegliche Nebenwirkung des Auslösens des Media Players vermeiden.
Hinweis: Der Telekommunikationsserver ist möglicherweise nicht sofort nach dem Klingelereignis aktiv. Damit dies zuverlässig funktioniert, kann es für die App hilfreich sein , MediaSessionManager.OnActiveSessionsChangedListener zu implementieren, um zu überwachen, wann der Telekommunikationsserver aktiv wird, bevor das Ereignis gesendet wird.
Aktualisieren:
In Android O muss man
ACTION_DOWN
vorher simulierenACTION_UP
, sonst hat das oben genannte keine Auswirkung. dh Folgendes wird benötigt:Da jedoch seit Android O ein offizieller Anruf zur Beantwortung eines Anrufs verfügbar ist (siehe obere Antwort), ist dieser Hack möglicherweise nicht mehr erforderlich, es sei denn, man hat vor Android O eine alte Kompilierungs-API-Stufe beibehalten.
quelle
Versuchen Sie
input keyevent 79
die Konstante für KeyEvent.KEYCODE_HEADSETHOOK , um die Antwort von @Muzikant ein wenig zu erläutern und sie ein wenig zu ändern, damit sie auf meinem Gerät ein bisschen sauberer funktioniert . Sehr grob:Verzeihen Sie die ziemlich schlechten Codierungskonventionen, ich bin mit Runtime.exec () -Aufrufen nicht allzu vertraut. Beachten Sie, dass mein Gerät weder gerootet ist noch Root-Rechte anfordert.
Das Problem bei diesem Ansatz ist, dass er nur unter bestimmten Bedingungen funktioniert (für mich). Das heißt, wenn ich den obigen Thread über eine Menüoption ausführe, die der Benutzer auswählt, während ein Anruf klingelt, wird der Anruf einwandfrei beantwortet. Wenn ich es von einem Empfänger aus starte, der den Status eingehender Anrufe überwacht, wird es vollständig ignoriert.
Auf meinem Nexus 5 eignet es sich daher gut für benutzergesteuerte Antworten und sollte dem Zweck eines benutzerdefinierten Anrufbildschirms entsprechen. Es funktioniert einfach nicht für automatisierte Anwendungen vom Typ Anrufsteuerung.
Bemerkenswert sind auch alle möglichen Einschränkungen, einschließlich der Tatsache, dass auch dies wahrscheinlich in ein oder zwei Updates nicht mehr funktioniert.
quelle
input keyevent 79
funktioniert gut auf Sony Xperia 5.0. Funktioniert beim Anrufen von einer Aktivität oder von einem Rundfunkempfänger.über die adb-Befehle So nehmen Sie einen Anruf von adb an
Denken Sie daran, dass Android Linux mit einer massiven JVM im Frontend ist. Sie können eine Befehlszeilen-App herunterladen und das Telefon rooten. Jetzt verfügen Sie über einen normalen Linux-Computer und eine Befehlszeile, die alle normalen Aufgaben ausführen. Führen Sie Skripte aus, Sie können sogar ssh darauf (OpenVPN-Trick)
quelle
Danke @notz die Antwort von arbeitet für mich am Lolillop. Damit dieser Code mit dem alten Android SDK funktioniert, können Sie diesen Code ausführen:
quelle
So schalten Sie die Freisprecheinrichtung ein, nachdem Sie Anrufe automatisch beantwortet haben.
Ich habe mein Problem oben mit setSpeakerphoneOn gelöst. Ich denke, es lohnt sich, hier etwas zu posten, da der Anwendungsfall für die automatische Beantwortung eines Telefonanrufs häufig auch eine nützliche Freisprecheinrichtung erfordert. Nochmals vielen Dank an alle in diesem Thread, was für ein großartiger Job.
Dies funktioniert für mich unter Android 5.1.1 auf meinem Nexus 4 ohne ROOT. ;)
Erlaubnis erforderlich:
Java Code:
quelle
Führen Sie den folgenden Befehl als root aus:
Weitere Details zur Simulation von Keyevents finden Sie hier .
Mit dieser von mir erstellten Basisklasse können Sie Befehle als Root in Ihrer App ausführen.
quelle
Testen Sie dies: Fügen Sie zuerst die Berechtigungen hinzu und verwenden Sie dann killCall (), um aufzulegen. Verwenden Sie answerCall (), um den Anruf anzunehmen
quelle
Zu Ihrer Information, wenn Sie daran interessiert sind, wie Sie einen laufenden Anruf auf Android O, Valter's, beenden können
Method 1: TelephonyManager.answerRingingCall()
funktioniert wenn Sie die von Ihnen Methode ändernendCall
.Es erfordert nur die
android.permission.CALL_PHONE
Erlaubnis .Hier ist der Code:
quelle