Android 8.0 Oreo ile güncelleme
Soru başlangıçta Android L desteği için sorulmuş olsa da, insanlar hala bu soruyu ve cevabı buluyor gibi görünüyor, bu nedenle Android 8.0 Oreo'da sunulan iyileştirmeleri açıklamaya değer. Geriye dönük uyumlu yöntemler hala aşağıda açıklanmaktadır.
Ne değişti?
Android 8.0 Oreo'dan başlayarak , TELEFON izin grubu ayrıca ANSWER_PHONE_CALLS iznini de içerir . İznin adından da anlaşılacağı gibi, bunu tutmak, uygulamanızın, kullanıcıyı yansıtma veya simüle etme yoluyla sistemde herhangi bir hackleme olmaksızın, uygun bir API çağrısı aracılığıyla gelen çağrıları programlı olarak kabul etmesine olanak tanır.
Bu değişikliği nasıl kullanacağız?
Daha eski Android sürümlerini destekliyorsanız, bu yeni API çağrısını bu eski Android sürümleri için desteği sürdürürken kapsülleyebilmeniz için çalışma zamanında sistem sürümünü kontrol etmelisiniz . Daha yeni Android sürümlerinde standart olduğu gibi, çalışma zamanında bu yeni izni almak için çalışma zamanında izin talep etmeyi takip etmelisiniz .
İzni aldıktan sonra, uygulamanız sadece TelecomManager'ın acceptRingingCall yöntemini çağırmalıdır . Bu durumda temel bir çağrı aşağıdaki gibi görünür:
TelecomManager tm = (TelecomManager) mContext
.getSystemService(Context.TELECOM_SERVICE);
if (tm == null) {
throw new NullPointerException("tm == null");
}
tm.acceptRingingCall();
Yöntem 1: TelephonyManager.answerRingingCall ()
Cihaz üzerinde sınırsız kontrole sahip olduğunuz zamanlar için.
Bu nedir?
Gizli, dahili bir yöntem olan TelephonyManager.answerRingingCall () vardır. Interweb'lerde tartışılan ve başlangıçta umut verici görünen ITelephony.answerRingingCall () için bir köprü görevi görür. Öyle değil geçerli 4.4.2_r1 sadece içinde taahhüt tanıtıldı olarak 83da75d Android 4.4 için KitKat ( 4.4.3_r1 üzerine çizgi 1537 taahhüt olarak) ve daha sonra "yeniden" f1e1e77 Lollipop (için 5.0.0_r1 üzerine hat 3138 ) nedeniyle nasıl Git ağacı yapılandırıldı. Bu, şu an itibariyle küçük pazar payına dayalı olarak muhtemelen kötü bir karar olan Lollipop'lu cihazları desteklemediğiniz sürece, bu rotaya giderken yine de geri dönüş yöntemleri sağlamanız gerektiği anlamına gelir.
Bunu nasıl kullanacağız?
Söz konusu yöntem, SDK uygulamalarının kullanımından gizlendiğinden, çalışma zamanı sırasında yöntemi dinamik olarak incelemek ve kullanmak için yansımayı kullanmanız gerekir . Düşünme konusuna aşina değilseniz, hızlıca Yansıma nedir ve neden yararlıdır? Okuyabilirsiniz. . Ayrıca, eğer ilgileniyorsanız , Trail: The Reflection API'de ayrıntıları daha derinlemesine inceleyebilirsiniz .
Ve bu kodda nasıl görünüyor?
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);
}
Bu gerçek olamayacak kadar iyi!
Aslında ufak bir sorun var. Bu yöntem tamamen işlevsel olmalıdır, ancak güvenlik yöneticisi arayanların android.permission.MODIFY_PHONE_STATE yapmasını ister . Bu izin, sistemin yalnızca kısmen belgelenmiş özellikleri kapsamındadır, çünkü 3. kişilerin dokunması beklenmez (bunun için belgelerden de görebileceğiniz gibi). Bunun <uses-permission>
için bir eklemeyi deneyebilirsiniz , ancak bu bir işe yaramayacaktır çünkü bu iznin koruma düzeyi imza | sistemdir ( 5.0.0_r1'deki core / AndroidManifest satır 1201'e bakın ).
Belirli "boru sözdizimi" ile ilgili ayrıntıları kaçırdığımızı görmek için 2012'de oluşturulan Sürüm 34785: Güncelleme android: koruma Düzeyi belgelerini okuyabilirsiniz , ancak etrafta yapılan deneylerden, tüm bunlar anlamına gelen bir "VE" İznin verilebilmesi için belirtilen bayrakların yerine getirilmesi gerekir. Bu varsayım altında çalışmak, başvurunuzu almanız gerektiği anlamına gelir:
Sistem uygulaması olarak kuruldu.
Bu iyi olmalı ve kullanıcılardan kurtarmada bir ZIP kullanarak yüklemelerini isteyerek gerçekleştirilebilir, örneğin, Google uygulamalarını önceden paketlenmemiş özel ROM'lara köklenirken veya yüklerken.
ROM olarak da bilinen sistem ile aynı imzayla imzalanmıştır.
Sorunların ortaya çıktığı yer burasıdır. Bunu yapmak için, çerçeveleri / tabanı imzalamak için kullanılan anahtarların elinizde olması gerekir. Nexus fabrika görüntüleri için yalnızca Google'ın anahtarlarına erişmeniz gerekmez, aynı zamanda diğer tüm OEM'lerin ve ROM geliştiricilerinin anahtarlarına da erişmeniz gerekir. Bu mantıklı görünmüyor, bu nedenle uygulamanızı özel bir ROM oluşturarak ve kullanıcılarınızdan buna geçiş yapmalarını isteyerek (bu zor olabilir) veya izin koruma seviyesinin atlanabileceği bir istismar bularak sistem anahtarları ile imzalatabilirsiniz. (bu da zor olabilir).
Ek olarak, bu davranış, 34792 Sayılı: Android Jelly Bean / 4.1: android.permission.READ_LOGS ile ilgili gibi görünmektedir .
TelephonyManager ile çalışmak kulağa hoş geliyor, ancak pratikte yapılması o kadar kolay olmayan uygun izni almadığınız sürece işe yaramayacaktır.
TelephonyManager'ı başka şekillerde kullanmaya ne dersiniz?
Ne yazık ki, harika araçları kullanmak için android.permission.MODIFY_PHONE_STATE'i tutmanızı gerektiriyor gibi görünüyor, bu da bu yöntemlere erişmekte zorlanacağınız anlamına geliyor.
Yöntem 2: servis çağrısı SERVİS KODU
Cihazda çalışan derlemenin belirtilen kodla çalışıp çalışmayacağını ne zaman test edebilirsiniz.
TelephonyManager ile etkileşime service
girmeden , çalıştırılabilir dosya aracılığıyla hizmetle etkileşim kurma olasılığı da vardır .
Bu nasıl çalışıyor?
Oldukça basit, ancak bu rota hakkında diğerlerine göre daha az belge var. Çalıştırılabilir dosyanın iki bağımsız değişken aldığından emin olduğumuzu biliyoruz - hizmet adı ve kod.
Hizmet adı biz kullanıma istediğim telefon .
Bu koşarak görülebilir service list
.
Kod biz kullanıma istiyoruz edilmiş görünen 6 ama şimdi görünüyor 5 .
O dayalı alınmış gibi görünüyor IBinder.FIRST_CALL_TRANSACTION şimdi birçok sürümleri için +5 (den 1.5_r4 için 4.4.4_r1 ) ancak yerel test sırasında kod 5 gelen aramayı cevaplamak için çalıştı. Lollipo her yerinde büyük bir güncelleme olduğu için, burada da değişmiş olan anlaşılabilir iç kısımlar.
Bu, komutuyla sonuçlanır service call phone 5
.
Bunu programlı olarak nasıl kullanıyoruz?
Java
Aşağıdaki kod, kavramın bir kanıtı olarak işlev görmesi için yapılmış kaba bir uygulamadır. Gerçekten devam etmek ve bu yöntemi kullanmak istiyorsanız, muhtemelen sorunsuz su kullanımı için yönergelere göz atmak ve muhtemelen Chainfire tarafından geliştirilmiş daha tam gelişmiş libsuperuser'a geçmek istersiniz .
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();
}
Belirgin
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
Bu gerçekten kök erişimi gerektiriyor mu?
Ne yazık ki öyle görünüyor. Üzerinde Runtime.exec kullanmayı deneyebilirsiniz , ancak bu rotada hiç şansım olmadı.
Bu ne kadar kararlı?
Sorduğuna sevindim Belgelenmemesi nedeniyle, bu, yukarıdaki görünen kod farkında gösterildiği gibi çeşitli sürümlerde kırılabilir. Hizmet adı muhtemelen çeşitli yapılarda telefon olarak kalmalıdır , ancak bildiğimiz kadarıyla, kod değeri aynı sürümün birden çok yapısında değişebilir (örneğin, OEM'in dış görünümüyle yapılan dahili değişiklikler) ve dolayısıyla kullanılan yöntemi bozabilir. Bu nedenle testin bir Nexus 4 (mako / occam) üzerinde yapıldığından bahsetmeye değer. Şahsen bu yöntemi kullanmamanızı tavsiye ederim, ancak daha kararlı bir yöntem bulamadığım için bunun en iyi atış olduğuna inanıyorum.
Orijinal yöntem: Kulaklık tuş kodu amaçları
Yerleşmeniz gereken zamanlar için.
Aşağıdaki bölüm kuvvetle etkilendi Bu yanıt ile Riley C .
Orijinal soruda yayınlanan simüle edilmiş kulaklıklı mikrofon seti amacı yöntemi, beklendiği gibi yayınlanıyor gibi görünüyor, ancak aramayı cevaplama amacına ulaşmış gibi görünmüyor. Bu amaçları yerine getirmesi gereken bir kod varmış gibi görünse de, bunlar önemsenmiyor, bu da bu yönteme karşı bir tür yeni karşı önlem olması gerektiği anlamına gelmelidir. Günlük de ilgi çekici bir şey göstermiyor ve kişisel olarak Android kaynağını araştırmanın, Google'ın yine de kullanılan yöntemi kolayca bozan küçük bir değişiklik yapma olasılığı nedeniyle faydalı olacağına inanmıyorum.
Şu anda yapabileceğimiz bir şey var mı?
Davranış, yürütülebilir girdi kullanılarak tutarlı bir şekilde yeniden oluşturulabilir. O kendisi için biz sadece geçmek, bir tuş kodu argüman alır KeyEvent.KEYCODE_HEADSETHOOK . Yöntem, kök erişimini bile gerektirmez, bu da onu genel halkın genel kullanım durumlarına uygun hale getirir, ancak yöntemde küçük bir dezavantaj vardır - kulaklık düğmesi basma etkinliği bir izin gerektirecek şekilde belirlenemez, yani gerçek gibi çalışır düğmeye basın ve tüm zincir boyunca kabarcıklar yükseliyor, bu da düğmeye basma simülasyonunu ne zaman yapacağınız konusunda dikkatli olmanız gerektiği anlamına geliyor, çünkü daha yüksek önceliğe sahip hiç kimse işleme hazır değilse müzik çaları çalmaya başlamak için tetikleyebilir. olay.
Kod mu?
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 ve üstü için güzel bir genel API var.
Android 8.0 Oreo'dan önce herkese açık bir API yoktur. Dahili API'ler sınırsızdır veya dokümantasyonsuzdur. Dikkatli hareket etmelisiniz.