2017-12-08 4 views
0

Meine App erstellt einen Kontakt im Android-Kontaktbuch mit einem speziellen SYNC4-Schlüssel, so dass wir unseren speziellen Kontakt (getrennt von anderen Android-Kontakten) nachschlagen können. Wir können den Kontakt auf einem HTC 10-Gerät jedoch nicht lesen. Ich habe über einige Unterschiede zwischen HTC-Geräten und anderen Android-Geräten bezüglich der Handhabung von Kontakten gelesen, aber leider keine gute Erklärung oder Lösung für dieses Problem gefunden.Abrufen von Android-Kontakt mit contentResolver auf HTC 10 gibt kein Ergebnis zurück

Die Schaffung des Kontakts funktioniert wie folgt:

private static final String SPECIAL_CONTACT_KEY = "_MY_SPECIAL_CONTACT_KEY_"; 

// Create an operation with the special SYN4 key 
ArrayList<ContentProviderOperation> ops = new ArrayList<>(); 
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); 
     builder.withValue(RawContacts.ACCOUNT_TYPE, null); 
     builder.withValue(RawContacts.ACCOUNT_NAME, null); 
     builder.withValue(RawContacts.SYNC4, SPECIAL_CONTACT_KEY); 
     ops.add(builder.build()); 

// Add a 'given name' to the list of operations 
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 
     builder.withValueBackReference(Data.RAW_CONTACT_ID, 0); 
     builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 
     builder.withValue(StructuredName.GIVEN_NAME, "givenName"); 
     ops.add(builder.build()); 

// Add a 'phone number with type work' to the list of operations 
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 
     builder.withValueBackReference(Data.RAW_CONTACT_ID, 0); 
     builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 
     builder.withValue(Phone.TYPE, Phone.TYPE_WORK); 
     builder.withValue(Phone.NUMBER, "phoneNumber"); 
     ops.add(builder.build()); 

// Add a 'note' to the list of operations (to be able to visually discern the contact from other contacts) 
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); 
     builder.withValueBackReference(Data.RAW_CONTACT_ID, 0); 
     builder.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE); 
     builder.withValue(Note.NOTE, "note"); 
     ops.add(builder.build()); 

ContentProviderResult[] result = App.getContext().getContentResolver().applyBatch(AUTHORITY, ops); 

Der Kontakt (e) kann wie folgt ermittelt werden:

// Retrieve our own contacts using the special SYNC4 key 
Uri uri = Phone.CONTENT_URI; 
String[] projection = {Phone.NUMBER}; 
String mySpecialSelection = RawContacts.SYNC4 + "='" + SPECIAL_CONTACT_KEY + "'"; 
Cursor cursor = App.getContext().getContentResolver().query(uri, projection, mySpecialSelection, null, null); 

Der Cursor mit der korrekten Kontaktdaten auf alle Gerät gefüllt ist , aber auf dem HTC ist der Cursor leer.

+0

, warum Sie mit 'SYNC4'? – pskink

+0

Um ehrlich zu sein, wurde es bereits von einem Kollegen benutzt, und mir wurde gesagt, dass es ein spezifischer Marker ist, um unseren Kontakt von anderen zu unterscheiden. Ich bin nicht sicher, was es tut, aber wenn Sie einen Rat für einen besseren Marker haben, sagen Sie bitte ;-) Sie denken, dass es mit dem HTC Problem zusammenhängt? –

Antwort

1

Sie können keinen Kontakt mit null ACCOUNT_NAME und ACCOUNT_TYPE erstellen, dies nennt man Zombie-Kontakte, und es gibt keine Garantie, dass sie auf dem Gerät verbleiben (nicht nur auf HTC-Geräten).

Wenn Sie neue Kontakte erstellen müssen, müssen Sie ein benutzerdefiniertes Konto für Ihre App erstellen und neue Kontakte/unverarbeitete Kontakte unter diesem Konto erstellen.

Siehe this und this. BTW, Sie brauchen kein SyncAdapter, aber es macht Dinge wie die Aktualisierung der Daten Ihres Kontakts einfacher und spielt gut mit dem Android-Ökosystem.

Sie können dann Ihre eigenen RawContacts durch Abfragen für ACCOUNT_TYPE = <your custom type> in Ihrer Abfrage finden.

+0

Das hat das Problem gelöst, danke! Die Beschreibung in den Links wurde jedoch sehr erweitert (einschließlich einer Option zur Anmeldung durch den Benutzer usw.). Ich werde meine Lösung in einer separaten Antwort unten beschreiben. –

0

Basierend auf the answer of marmor Ich habe die Kontoerstellung vereinfacht in den Links beschrieben. Ich brauche meinen Benutzer nicht, um ein Konto/Login usw. zu erstellen, aber ich erstelle nur ein Konto, inkl. ein einziger Kontakt, das ist alles was ich brauche. Hier ist eine vereinfachte Version von meinem Code:

ich eine MyAppAccountManager Klasse wie folgt aus:

public class MyAppAccountManager 
{ 
    public boolean createMyAppAccountIfNotExists(Context context) 
    { 
     return doesMyAppAccountExist(context) || createNewMyAppAccount(context); 
    } 

    public boolean createNewMyAppAccount(Context context) 
    { 
     Account account = new Account(context.getString(R.string.account_name), context.getString(R.string.account_type)); 
     boolean accountCreated = AccountManager.get(context).addAccountExplicitly(account, context.getString(R.string.account_password), null); 
     if (accountCreated) 
     { 
      Log.d("TAG", "Account created"); 
     } 
     else 
     { 
      Log.d("TAG", "Account creation failed."); 
     } 
     return accountCreated; 
    } 

    public boolean doesMyAppAccountExist(Context context) 
    { 
     return AccountManager.get(context).getAccountsByType(context.getString(R.string.account_type)).length > 0; 
    } 
} 

Wenn ich den Kontakt zu erstellen, ich habe nicht die SYNC4 SPECIAL_CONTACT_KEY mehr verwenden, aber das Konto (Typ & -name):

if (!new MyAppAccountManager().createMyAppAccountIfNotExists(context)) 
{ 
    throw new UnableToCreateContact("Could not find or create MyApp account"); 
} 

ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); 
     builder.withValue(RawContacts.ACCOUNT_TYPE, context.getString(R.string.account_type)); 
     builder.withValue(RawContacts.ACCOUNT_NAME, context.getString(R.string.account_name)); 
     ops.add(builder.build()); 

Außerdem muss ich meine Kontoauthentifizierer in meinem Manifest beschreiben:

<service 
     android:name=".service.MyAppAuthenticatorService" 
     android:exported="false"> 
     <intent-filter> 
      <action android:name="android.accounts.AccountAuthenticator"/> 
     </intent-filter> 
     <meta-data 
      android:name="android.accounts.AccountAuthenticator" 
      android:resource="@xml/authenticator"/> 
    </service> 

die meinem Authenticator Service-Punkte:

public class MyAppAuthenticatorService 
     extends Service 
{ 
    @Override 
    public IBinder onBind(Intent intent) 
    { 
     MyAppAuthenticator authenticator = new MyAppAuthenticator(this); 
     return authenticator.getIBinder(); 
    } 
} 

ein Standard MyAppAuthenticator erforderlich:

public class MyAppAuthenticator 
     extends AbstractAccountAuthenticator 
{ 
    public MyAppAuthenticator(Context context) 
    { 
     super(context); 
    } 

    @Override 
    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) 
    { 
     throw new UnsupportedOperationException(); 
    } 

    ... etc 

Das Manifest auch Authenticator verweist.xml:

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" 
        android:accountType="@string/account_type" 
        android:icon="@drawable/ic_launcher" 
        android:label="@string/account_name" 
        android:smallIcon="@drawable/ic_launcher"/> 

Endlich - nur das Bild komplett zu machen - es gibt die String-Konstanten:

<string name="account_type">my.app.applicationid.account</string> 
<string name="account_name">@string/app_title</string> 
<string name="account_password">password</string> 
Verwandte Themen