Android 8.0Oreoで更新
質問は元々AndroidLのサポートを求められていましたが、人々はまだこの質問と回答に答えているようです。そのため、Android 8.0Oreoで導入された改善点について説明する価値があります。下位互換性のある方法については、以下で説明します。
何が変わったの?
以降ではアンドロイド8.0オレオ、PHONEの許可グループはまた、含まれていANSWER_PHONE_CALLSの許可を。権限の名前が示すように、権限を保持すると、アプリは、リフレクションを使用したりユーザーをシミュレートしたりしてシステムをハッキングすることなく、適切なAPI呼び出しを介して着信呼び出しをプログラムで受け入れることができます。
この変更をどのように利用しますか?
あなたは必要があり、実行時にシステムのバージョンを確認し、これらの古いAndroidのバージョンのサポートを維持しながら、あなたは、この新しいAPI呼び出しをカプセル化できるように、古いAndroidのバージョンをサポートしている場合。あなたは従うべきで、実行時に許可を要求する、新しい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を原因どのように) Gitツリーが構造化されました。つまり、Lollipopを搭載したデバイスのみをサポートする場合を除きます。これは、現時点でのわずかな市場シェアに基づくとおそらく悪い決定ですが、このルートを進む場合は、フォールバック方法を提供する必要があります。
これをどのように使用しますか?
問題のメソッドはSDKアプリケーションの使用から隠されているため、リフレクションを使用して、実行時にメソッドを動的に調べて使用する必要があります。リフレクションに慣れていない場合は、リフレクションとは何ですか。なぜそれが役立つのでしょうか。。興味がある場合は、Trail:The ReflectionAPIで詳細を掘り下げることもできます。
そして、それはコードでどのように見えますか?
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);
}
これはあまりにも良すぎて真実ではありません!
実際、ちょっとした問題が1つあります。このメソッドは完全に機能するはずですが、セキュリティマネージャーは、呼び出し元がandroid.permission.MODIFY_PHONE_STATEを保持することを望んでいます。この許可は、サードパーティがそれに触れることを期待されていないため、システムの部分的に文書化された機能の領域にあります(システムのドキュメントからわかるように)。を追加し<uses-permission>
てみることができますが、この権限の保護レベルは署名|システムであるため、うまくいきません(5.0.0_r1のcore / AndroidManifestの1201行目を参照)。
あなたは読むことができる問題34785を:のProtectionLevelドキュメント:アップデートは、Android、我々は特定の「パイプの構文」の詳細が欠けていることを確認するために2012年に戻ってを作成しましたが、周りの実験から、「AND」のすべてを意味するものとして機能しなければならない表示されます許可を与えるには、指定されたフラグを満たす必要があります。その仮定の下で作業すると、アプリケーションが必要になることを意味します。
システムアプリケーションとしてインストールされます。
これは問題ないはずであり、まだパッケージ化されていないカスタムROMにGoogleアプリをルート化またはインストールする場合など、リカバリでZIPを使用してインストールするようにユーザーに依頼することで実現できます。
フレームワーク/ベース、別名システム、別名ROMと同じ署名で署名されています。
ここで問題が発生します。これを行うには、フレームワーク/ベースの署名に使用されるキーを手に入れる必要があります。NexusファクトリイメージのGoogleのキーにアクセスする必要があるだけでなく、他のすべてのOEMおよびROM開発者のキーにもアクセスする必要があります。これはもっともらしいとは思えないので、カスタムROMを作成してユーザーに切り替えるように依頼するか(難しい場合があります)、アクセス許可保護レベルをバイパスできるエクスプロイトを見つけることで、システムキーでアプリケーションに署名させることができます。 (これも難しいかもしれません)。
さらに、この動作は、Issue 34792:Android Jelly Bean / 4.1:android.permission.READ_LOGSが機能しなくなり、文書化されていない開発フラグとともに同じ保護レベルを利用するようになりました。
TelephonyManagerの操作は良いように聞こえますが、実際にはそれほど簡単ではない適切な許可を取得しない限り、機能しません。
TelephonyManagerを他の方法で使用するのはどうですか?
残念ながら、クールなツールを使用するにはandroid.permission.MODIFY_PHONE_STATEを保持する必要があるようです。つまり、これらのメソッドにアクセスするのに苦労することになります。
方法2:サービスコールサービスコード
デバイスで実行されているビルドが指定されたコードで動作することをテストできる場合。
TelephonyManagerと対話できなくても、service
実行可能ファイルを介してサービスと対話する可能性もあります。
これはどのように作動しますか?
かなり単純ですが、このルートに関するドキュメントは他のルートよりもさらに少なくなっています。実行可能ファイルがサービス名とコードの2つの引数を受け取ることは確かです。
サービス名、我々が使用したいです電話。
これは、を実行することで確認できますservice list
。
コード我々はされているように使用したい6が、今のようです5。
現在、多くのバージョン(1.5_r4から4.4.4_r1)でIBinder.FIRST_CALL_TRANSACTION + 5に基づいているようですが、ローカルテスト中に、コード5が着信呼び出しに応答するように機能しました。Lollipoはあらゆる面で大規模な更新であるため、ここでも内部が変更されていることは理解できます。
これは、のコマンドで発生しservice call phone 5
ます。
これをプログラムでどのように利用しますか?
Java
次のコードは、概念実証として機能するように作成された大まかな実装です。実際にこの方法を使用したい場合は、問題のないsuの使用に関するガイドラインを確認し、Chainfireによってより完全に開発されたlibsuperuserに切り替えることをお勧めします。
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)で行われたことに言及する価値があります。個人的にはこの方法を使わないようにアドバイスしたいのですが、もっと安定した方法が見つからないので、これがベストショットだと思います。
元の方法:ヘッドセットのキーコードインテント
あなたが落ち着かなければならない時のために。
次のセクションは、RileyCによるこの回答の影響を強く受けました。
元の質問に投稿されたシミュレートされたヘッドセットインテントメソッドは、予想どおりにブロードキャストされているように見えますが、通話に応答するという目標を達成していないようです。これらの意図を処理するコードが配置されているように見えますが、それらは単に気にされていません。つまり、この方法に対して何らかの新しい対策を講じる必要があります。ログにも関心のあるものは何も表示されていません。Googleがわずかな変更を導入して、とにかく使用されている方法を簡単に破る可能性があるという理由だけで、Androidソースを掘り下げる価値があるとは個人的には思いません。
今できることはありますか?
動作は、入力実行可能ファイルを使用して一貫して再現できます。キーコード引数を取り、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.0Oreo以降用の優れたパブリックAPIがあります。
Android 8.0Oreoより前のパブリックAPIはありません。内部APIは立ち入り禁止であるか、単にドキュメントがありません。注意して続行する必要があります。