2012-02-29 12 views
15

Así que acabo de implementar un widget para mi aplicación. Obtiene sus datos de la base de datos a través de mi ContentProvider. Defino mi propia lectura/escritura en permisos en mi manifiesto, afirman que los uso (no parece hacer una diferencia), y ellos requieren en el proveedor de contenidos:Widget con proveedor de contenido; imposible de usar ReadPermission?

<!-- Define my permissions for the provider --> 
<permission 
    android:name="com.nononsenseapps.notepad.permissions.read" 
    android:description="@string/permission_read_desc" 
    android:label="@string/permission_read_label" 
    android:permissionGroup="android.permission-group.PERSONAL_INFO" 
    android:protectionLevel="normal" /> 
<permission 
    android:name="com.nononsenseapps.notepad.permissions.write" 
    android:description="@string/permission_write_desc" 
    android:label="@string/permission_write_label" 
    android:permissionGroup="android.permission-group.PERSONAL_INFO" 
    android:protectionLevel="normal" /> 
...... 
<uses-permission android:name="com.nononsenseapps.notepad.permissions.read" /> 
<uses-permission android:name="com.nononsenseapps.notepad.permissions.write" /> 
<uses-permission android:name="android.permission.BIND_REMOTEVIEWS" /> 
...... 
<provider 
     android:name=".NotePadProvider" 
     android:authorities="com.nononsenseapps.NotePad" 
     android:enabled="true" 
     android:exported="true" 
     android:label="@string/app_name" 
     android:readPermission="com.nononsenseapps.notepad.permissions.read" 
     android:syncable="true" 
     android:writePermission="com.nononsenseapps.notepad.permissions.write" > 
     <grant-uri-permission android:pathPattern=".*" /> 
    </provider> 

actualizo mi aparato a través de una Service (según el tutorial Widget):

<!-- List Widget --> 
    <receiver android:name="com.nononsenseapps.notepad.widget.ListWidgetProvider" > 
     <intent-filter> 
      <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 
     </intent-filter> 

     <meta-data 
      android:name="android.appwidget.provider" 
      android:resource="@xml/listwidgetinfo" /> 
    </receiver> 

    <service 
     android:name="com.nononsenseapps.notepad.widget.ListWidgetService" 
     android:exported="false" 
     android:permission="android.permission.BIND_REMOTEVIEWS" /> 

Y eso Service a su vez hace esto (con un montón de código no incluido):

/** 
* This is the service that provides the factory to be bound to the collection 
* service. 
*/ 
public class ListWidgetService extends RemoteViewsService { 

@Override 
public RemoteViewsFactory onGetViewFactory(Intent intent) { 
    return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 
} 
} 

/** 
* This is the factory that will provide data to the collection widget. 
*/ 
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 

public StackRemoteViewsFactory(Context context, Intent intent) { 
    mContext = context; 
    observer = new ListChecker(null); 
    mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 
      AppWidgetManager.INVALID_APPWIDGET_ID); 
} 
public void onDataSetChanged() { 
    Log.d(TAG, "onDataSetChanged"); 
    // Refresh the cursor 
    if (mCursor != null) { 
     mCursor.close(); 
    } 

    // Get widget settings 
    SharedPreferences settings = mContext.getSharedPreferences(
      ListWidgetConfigure.getSharedPrefsFile(mAppWidgetId), 
      mContext.MODE_PRIVATE); 
    if (settings != null) { 
     String listWhere = settings.getString(ListWidgetConfigure.LIST_WHERE, null); 
     listId = settings.getLong(ListWidgetConfigure.LIST_ID, -1); 
     String sortOn = settings.getString(ListWidgetConfigure.SORT_ON, NotePad.Notes.ALPHABETIC_ASC_ORDER); 

     mCursor = mContext.getContentResolver().query(
       NotePadProvider.CONTENT_VISIBLE_URI, PROJECTION, listWhere, null, 
       sortOn); 
    } 
} 
} 

Así que aquí está el problema: cuando agrego el widget a la pantalla de inicio, un SecurityException se arroja inmediatamente dentro del método onDataSetChanged() cuando intento consultar al proveedor. Esto parece ser porque la pantalla de inicio no tiene el permiso para leer mi proveedor de contenido. Mi intuición era que no sería un problema ya que mi propia aplicación tiene el permiso, y el servicio es obviamente una parte de mi aplicación.

Todo funciona muy bien si elimino el requisito ReadPermission del proveedor. Pero parece un problema de seguridad porque cualquier aplicación puede acceder al proveedor sin que el usuario tenga que aprobar nada.

Entonces, ¿hay alguna manera de utilizar un proveedor con una ReadPermission con un widget? ¿O está obligado a utilizar un proveedor exportado no seguro?

+0

estoy teniendo el mismo problema, has encontrado ninguna solución todavía? Si es así, ¿podrías describir como respuesta cómo lo arreglaste? –

+0

Tristemente no. No encontré ninguna solución, así que simplemente eliminé el permiso requerido :( –

+0

También teniendo este problema ... – JMRboosties

Respuesta

13

Pude encontrar la respuesta here, el mérito es para Kostya Vasilyev.

Si bien el contexto es realmente correcto, está vinculado al proceso incorrecto.

Así que la clave es hacer esto:

public void onDataSetChanged() { 
    // Revert back to our process' identity so we can work with our 
    // content provider 
    final long identityToken = Binder.clearCallingIdentity(); 

    // Update your cursor or whaterver here 
    // ... 

    // Restore the identity - not sure if it's needed since we're going 
    // to return right here, but it just *seems* cleaner 
    Binder.restoreCallingIdentity(identityToken); 
} 
+0

Respuesta perfecta Esto resuelve el problema, incluso sin establecer permisos de lectura/escritura en el proveedor de contenido, simplemente utilizándolo con el conjunto exportado en "falso". –

0

Lo más probable es que esté utilizando el contexto del widget, que será el de la pantalla de inicio. Prueba la siguiente línea en su código:

mCursor = ListWidgetService.this.getContentResolver().query(
      NotePadProvider.CONTENT_VISIBLE_URI, PROJECTION, listWhere, null, 
      sortOn); 

Nota cómo he sustituido el mContext.. Un servicio es un contexto propio, que debe tener el permiso correcto, dado su manifiesto.

+0

En realidad, si miras el código, ves que el contexto que se pasa a RemoteViewsFactory es exactamente lo que sugieres. Sin embargo, tu respuesta ¡investigo más y pude encontrar la solución! Envíelo como respuesta –

+0

De hecho, tienes razón, no estoy seguro de cómo me lo perdí :) Pero me alegro de que te ponga en el camino correcto de todos modos :) –

Cuestiones relacionadas