samsung - Capacidad de llamada de teléfono del dispositivo Android
pasar aplicaciones instaladas a otro android (7)
Creo que un mejor enfoque sería consultar el PackageManager para detectar si las características de telefonía están incluso disponibles en el dispositivo. Un dispositivo solo debe tener características de telefonía si tiene un teléfono. Probé esto en un Nexus 7, que no tiene teléfono, y funciona. No tengo un dispositivo con un teléfono para probar el caso contrario.
PackageManager pm = getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)){
//has Telephony features.
}
¿Cómo puedo saber si un dispositivo determinado tiene la capacidad de hacer llamadas telefónicas?
Por ejemplo, mi Galaxy Tablet no puede, no es un teléfono. Quiero detectar eso antes de hacer una llamada a isIntentAvailable(context, Intent.ACTION_DIAL)
. He intentado comprobar el isIntentAvailable
para esto, pero ese no parece ser el camino a seguir.
La mayoría de estas soluciones funcionan aquí en algunos casos, pero no en todos.
Como indica @DanJ. No hay una manera fácil de lograr esto.
Tuve problemas para controlar PackageManager.FEATURE_TELEPHONY
y getPhoneType
, ya que ambos parecen verificar si el dispositivo es capaz en teoría, y asumir que puede realizar llamadas si este es el caso. Esto se rompe si tiene un teléfono sin tarjeta SIM, y posiblemente si no tiene cobertura / fuera del alcance. Lo mismo ocurre con el enfoque de verificar qué aplicaciones pueden manejar una llamada, porque la aplicación del teléfono todavía está instalada, pero se romperá (al menos en mi galaxy s3) cuando no haya SIM.
Sin embargo, hay una vez que puede hacer un control que me parece que funciona para la mayoría de los casos, y es para verificar el subscriberId
su teléfono, básicamente "cuál es el nombre / id de su proveedor de red".
Puedes hacerlo:
if(((TelephonyManager)getContext()
.getSystemService(Context.TELEPHONY_SERVICE))
.getSubscriberId() == null) {
//No network id ~= can''t make calls
}
Aquí comprobamos si no tenemos una red, por lo tanto podemos suponer "de manera segura" que el dispositivo no puede hacer una llamada. Este enfoque da falsos negativos en el caso de que tenga un teléfono VoIP o tenga algo así como Skype instalado.
Este enfoque requiere que agregue un permiso:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
La solución de @ TedHopp requiere el permiso READ_SMS
que me parece más intrusivo.
Ohh cómo me gustaría phone.canMakeCallsWithoutCrashing()
era una cosa en la API de Android.
Los dispositivos no necesitan necesariamente Context.TELEPHONY_SERVICE
para realizar llamadas telefónicas. Considere lo que sucede si instala Skype:
- Ingrese un número de teléfono en la aplicación Dialer / Phone y presione "Llamar".
- Aparece una ventana emergente titulada "Complete action using" y ofrece aplicaciones "Dialer" o "Skype" (también podría incluir otras aplicaciones).
Por lo tanto, creo que Skype funcionaría en un dispositivo solo wifi sin capacidades de teléfono (según Context.TELEPHONY_SERVICE
).
Creo que tenía razón con su idea original, pero necesita verificar qué aplicaciones están registradas para manejar Intent.ACTION_CALL
lugar de Intent.ACTION_DIAL
, por ejemplo
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:5551231234"));
List<ResolveInfo> callAppsList =
context.getPackageManager().queryIntentActivities(callIntent, 0);
Sin embargo, no conozco ninguna forma confiable y directa de averiguar si esas aplicaciones serán capaces de manejar la llamada telefónica. Considere estos casos:
1) Un Xoom solo wifi con Skype instalado. Necesita una conexión wifi válida, y el usuario debe haber configurado Skype para usar su cuenta, de lo contrario, la llamada no tendrá éxito.
2) Un dispositivo habilitado para telefonía sin tarjeta SIM, o una tarjeta SIM que está bloqueada o se ha agotado. El dispositivo cree que puede manejar la telefonía, pero la llamada da como resultado un error "No registrado en la red".
3) Un dispositivo habilitado para telefonía sin wifi o conexión móvil (o porque está en modo Avión / Vuelo). El dispositivo cree que puede manejar la telefonía, pero la llamada fallará.
Hay formas en que puede detectar algunos de estos escenarios (por ejemplo, inspeccionando getSystemService(Context.TELEPHONY_SERVICE).getSimState()
), pero creo que esto probablemente conduzca a un código frágil que se puede romper cuando las cosas cambien en el futuro. Por ejemplo, ¿siempre podría detectar de forma fiable qué aplicación de la lista es la aplicación Dialer / Phone predeterminada? ¿Qué pasa si Android cambió el nombre del paquete en una versión posterior?
Afortunadamente eso le dio información útil: ¡quería mostrar que esto es más complicado de lo que parece a primera vista!
No he comprobado esto todavía, pero aquí hay una solución que se me ocurrió que parece que debería funcionar bien. No creo que esto requiera ningún permiso especial, ya que solo está buscando bools establecidos por la fabricación.
static boolean isRunningOnPhone(Context context){
UiModeManager uiModeManager = (UiModeManager) context.getSystemService(UI_MODE_SERVICE);
PackageManager packageManager = context.getPackageManager();
boolean a = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
boolean b = packageManager.hasSystemFeature(PackageManager.FEATURE_SIP_VOIP) || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA) || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
boolean c = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
boolean d;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
d = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}else {
d = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR);
}
boolean e = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION);
boolean f = uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_APPLIANCE;
boolean g = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
g = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_WATCH);
}
return a && b && c && d && e && f && g;
}
Puede marcar solo la función de TELEFONÍA o GSM y CDMA por separado:
private boolean hasTelephony() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}
o
private boolean hasGsmOrCdma() {
PackageManager pm = getPackageManager();
boolean gsmSupported = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_GSM);
boolean cdmaSupported = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
//if necessary write somehow what exactly the devise supports
return gsmSupported || cdmaSupported;
}
¡funciona bien!
Steve,
Consulte TelephonyManager
. Tiene la función getPhoneType()
que devolverá PHONE_TYPE_NONE
en su caso.
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getPhoneType()
== TelephonyManager.PHONE_TYPE_NONE)
{
// no phone
}
EDITAR Me sorprende que vuelva PHONE_TYPE_CDMA
. Aquí hay otra posibilidad:
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
== null)
{
// no phone
}
Esto requerirá el permiso READ_PHONE_STATE
.