2012-02-29 12 views
15

così ho appena implementato un widget per la mia app. Ottiene i suoi dati dal database attraverso il mio ContentProvider. Definisco la mia propria lettura/scrittura-permissions nel mio manifesto, stato che li uso (non sembra fare la differenza), e li richiedono nel provider di contenuti:Widget con provider di contenuti; impossibile usare 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> 

aggiorno il mio widget di attraverso un Service (come per il widget di tutorial):

<!-- 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" /> 

E che Service a sua volta fa questo (con un mucchio di codice non incluso):

/** 
* 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); 
    } 
} 
} 

Quindi, ecco il problema: quando aggiungo il widget per la homescreen, un SecurityException è subito gettato all'interno del metodo onDataSetChanged() quando provo ad interrogare il provider. Ciò sembra essere dovuto al fatto che la homescreen non ha il permesso di leggere il mio fornitore di contenuti. La mia intuizione era che non sarebbe stato un problema dato che la mia app ha il permesso e il servizio è ovviamente parte della mia app.

Tutto funziona perfettamente se rimuovo il requisito ReadPermission dal provider. Ma sembra un problema di sicurezza perché ogni app può accedere al provider senza che l'utente debba approvare nulla.

Quindi c'è un modo per utilizzare un provider con un ReadPermission con un widget? O sei costretto a utilizzare un fornitore esportato non garantito?

+0

Sto avendo lo stesso identico problema, hai trovato qualche soluzione ancora? In tal caso, potresti descrivere come risposta come l'hai risolto? –

+0

Purtroppo no. Trovato nessuna soluzione quindi ho appena rimosso l'autorizzazione richiesta :( –

+0

Anche avendo questo problema ... – JMRboosties

risposta

13

Sono stato in grado di trovare la risposta here, il credito va a Kostya Vasilyev.

Mentre il contesto è in realtà corretto, è destinato al processo sbagliato.

Così è la chiave per fare questo:

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

Risposta perfetta Questo risolve il problema, anche senza impostare permessi di lettura/scrittura sul contentprovider, semplicemente usandolo con il set esportato su "false". –

0

Molto probabilmente, è perché si sta utilizzando il contesto del widget, che sarà quello della schermata iniziale. Provare la seguente riga nel codice:

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

Nota come ho sostituito il mContext.. Un servizio è un contesto a sé stante, che dovrebbe avere l'autorizzazione corretta, dato il manifest.

+0

In realtà, se si guarda il codice si vede che il contesto passato a RemoteViewsFactory è esattamente ciò che si suggerisce. me indagare ulteriormente e sono stato in grado di trovare la soluzione! Pubblicato come risposta. –

+0

in effetti, hai ragione, non so come ho perso che :) Ma sono contento che si mette sulla strada giusta in ogni caso :) –

Problemi correlati