android sms android-contentprovider

Android KitKat(API 19): ¿cómo escribir mensajes en el proveedor de contenido de SMS, sin enviarlos, desde la aplicación no predeterminada?



android-contentprovider (1)

La clase SmsWriteOpUtils utiliza la reflexión para acceder a los métodos del Servicio AppOpsManager para habilitar / deshabilitar el acceso de escritura de una aplicación de SMS no predeterminada al Proveedor de SMS en el Nivel API 19 (KitKat). Una vez configurado, el modo de acceso de una aplicación se mantendrá hasta que se restablezca o la aplicación se desinstale.

Habilitar el acceso de escritura de una aplicación le permite a esa aplicación todos los métodos estándar de interacción con el proveedor de SMS, incluidos insert() y delete() .

Tenga en cuenta que esta clase no verifica el nivel de API y que aún se requiere el permiso WRITE_SMS .

import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public final class SmsWriteOpUtils { private static final int WRITE_OP_CODE = 15; public static boolean isWriteEnabled(Context context) { int result = checkOp(context); return result == AppOpsManager.MODE_ALLOWED; } public static boolean setWriteEnabled(Context context, boolean enabled) { int mode = enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED; return setMode(context, mode); } private static int checkOp(Context context) { try { Method checkOpMethod = AppOpsManager.class.getMethod("checkOp", Integer.TYPE, Integer.TYPE, String.class); AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int uid = context.getApplicationInfo().uid; String packageName = context.getPackageName(); return checkOpMethod.invoke(appOpsManager, WRITE_OP_CODE, uid, packageName); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } return -1; } private static boolean setMode(Context context, int mode) { try { Method setModeMethod = AppOpsManager.class.getMethod("setMode", Integer.TYPE, Integer.TYPE, String.class, Integer.TYPE); AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int uid = context.getApplicationInfo().uid; String packageName = context.getPackageName(); setModeMethod.invoke(appOpsManager, WRITE_OP_CODE, uid, packageName, mode); return true; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } return false; } }

Ejemplo de uso:

boolean canWriteSms; if(!SmsWriteOpUtils.isWriteEnabled(getApplicationContext())) { canWriteSms = SmsWriteOpUtils.setWriteEnabled(getApplicationContext(), true); } ...

NB: para aplicaciones de usuario normales, esto solo funciona en el nivel de API 19 (KitKat). El agujero fue parchado en versiones posteriores.

Estoy tratando de crear una aplicación de Android que escriba mensajes en el cuadro Enviado del sistema. Estos mensajes no deben enviarse a través de la red GSM al destinatario, la idea es solo escribirlos en el proveedor de contenido enviado.

Por ahora, tengo este código:

Archivo de manifiesto

<uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.WRITE_SMS"/>

Clase de Java

private final String SENT_SMS_CONTENT_PROVIDER_URI_OLDER_API_19 = "content://sms/sent"; ContentValues values = new ContentValues(); values.put("address", mNumber); values.put("body", mMessage); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) mContext.getContentResolver().insert(Telephony.Sms.Sent.CONTENT_URI, values); else mContext.getContentResolver().insert(Uri.parse(SENT_SMS_CONTENT_PROVIDER_URI_OLDER_API_19), values);

Para un dispositivo con una versión API inferior a 19, esta implementación funciona bien. Para estas versiones sdk anteriores, solo es necesario acceder al proveedor de contenido definido por el contenido uri : // sms / sent .

Para las versiones más nuevas de SDK, esto no funciona. Aparentemente, Android cambió su forma de administrar el módulo de SMS en el lanzamiento de KitKat. Según el siguiente artículo, solo la aplicación de SMS predeterminada puede escribir y actualizar el nuevo proveedor de contenido de SMS (android.provider.Telephony.Sms.Sent - el contenido anterior: // sms / sent tampoco está disponible):

Teniendo en cuenta el comportamiento de esta aplicación, no tiene sentido convertirla en la aplicación de SMS predeterminada. Esta aplicación no necesita leer mensajes SMS del proveedor de contenido y no debe enviar ningún mensaje por SmsManager.getDefault (). SendTextMessage. Lo único que debe hacer es escribir algunos mensajes en el proveedor enviado.

Como puede comprender, tampoco es aceptable y factible solicitar al usuario que cambie la aplicación predeterminada a la mía y luego vuelva a la aplicación de SMS anterior, cada vez que sea necesario escribir un mensaje en el mensaje Enviado (esto se sugiere en la sección "Consejos para las aplicaciones de copia de seguridad y restauración de SMS" en el Blogspot de desarrolladores de Android).

El siguiente artículo revela algunas formas de mostrar la opción OP_WRITE_SMS:

Desafortunadamente, el siguiente código dejó de funcionar para Android 4.4.2:

Intent intent = new Intent(); intent.setClassName("com.android.settings", "com.android.settings.Settings"); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); intent.putExtra(":android:show_fragment", "com.android.settings.applications.AppOpsSummary"); startActivity(intent);

Estoy sin soluciones para superar este problema.