updating the SampleSyncAdapter sample to add stream item and photo code

Change-Id: I6d44ea3f912a3d1e52695bda785c81ff527160d5
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 285abfb..48f6fad 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -45,8 +45,12 @@
         android:name="android.permission.READ_SYNC_SETTINGS" />
     <uses-permission
         android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-permission
+        android:name="android.permission.READ_SOCIAL_STREAM" />
+    <uses-permission
+        android:name="android.permission.WRITE_SOCIAL_STREAM" />
 
-    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14"/>
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
 
     <application
         android:icon="@drawable/icon"
diff --git a/samples/SampleSyncAdapter/res/raw/img1.jpg b/samples/SampleSyncAdapter/res/raw/img1.jpg
new file mode 100644
index 0000000..24a492c
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/raw/img1.jpg
Binary files differ
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
index 3a9c879..f70547b 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java
@@ -26,6 +26,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class handles execution of batch mOperations on Contacts provider.
@@ -52,24 +53,27 @@
         mOperations.add(cpo);
     }
 
-    public Uri execute() {
-        Uri result = null;
+    public List<Uri> execute() {
+        List<Uri> resultUris = new ArrayList<Uri>();
 
         if (mOperations.size() == 0) {
-            return result;
+            return resultUris;
         }
         // Apply the mOperations to the content provider
         try {
             ContentProviderResult[] results = mResolver.applyBatch(ContactsContract.AUTHORITY,
                     mOperations);
-            if ((results != null) && (results.length > 0))
-                result = results[0].uri;
+            if ((results != null) && (results.length > 0)){
+                for (int i = 0; i < results.length; i++){
+                    resultUris.add(results[i].uri);
+                }
+            }
         } catch (final OperationApplicationException e1) {
             Log.e(TAG, "storing contact data failed", e1);
         } catch (final RemoteException e2) {
             Log.e(TAG, "storing contact data failed", e2);
         }
         mOperations.clear();
-        return result;
+        return resultUris;
     }
 }
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 6b2dfb1..dbda0b6 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -24,7 +24,10 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -38,8 +41,14 @@
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.Settings;
 import android.provider.ContactsContract.StatusUpdates;
+import android.provider.ContactsContract.StreamItemPhotos;
+import android.provider.ContactsContract.StreamItems;
 import android.util.Log;
 
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -235,6 +244,43 @@
     }
 
     /**
+     * Demonstrate how to add stream items and stream item photos to a raw
+     * contact. This just adds items for all of the contacts for this sync
+     * adapter with some locally created text and an image. You should check
+     * for stream items on the server that you are syncing with and use the
+     * text and photo data from there instead.
+     *
+     * @param context The context of Authenticator Activity
+     * @param rawContacts The list of users we want to update
+     */
+    public static void addStreamItems(Context context, List<RawContact> rawContacts,
+             String accountName, String accountType) {
+        final ContentResolver resolver = context.getContentResolver();
+        final BatchOperation batchOperation = new BatchOperation(context, resolver);
+        String text = "This is a test stream item!";
+        String message = "via SampleSyncAdapter";
+        for (RawContact rawContact : rawContacts) {
+           addContactStreamItem(context, lookupRawContact(resolver,
+                   rawContact.getServerContactId()), accountName, accountType,
+                   text, message, batchOperation );
+        }
+        List<Uri> streamItemUris = batchOperation.execute();
+
+        // Stream item photos are added after the stream items that they are
+        // associated with, using the stream item's ID as a reference.
+
+        for (Uri uri : streamItemUris){
+          // All you need is the ID of the stream item, which is the last index
+          // path segment returned by getPathSegments().
+          long streamItemId = Long.parseLong(uri.getPathSegments().get(
+                  uri.getPathSegments().size()-1));
+          addStreamItemPhoto(context, resolver, streamItemId, accountName,
+                  accountType, batchOperation);
+        }
+        batchOperation.execute();
+    }
+
+    /**
      * After we've finished up a sync operation, we want to clean up the sync-state
      * so that we're ready for the next time.  This involves clearing out the 'dirty'
      * flag on the synced contacts - but we also have to finish the DELETE operation
@@ -518,7 +564,7 @@
      * But it's a useful demo to see how it's done.
      *
      * @param context the Authenticator Activity context
-     * @param rawContact the contact who's status we should update
+     * @param rawContact the contact whose status we should update
      * @param batchOperation allow us to batch together multiple operations
      */
     private static void updateContactStatus(Context context, RawContact rawContact,
@@ -550,6 +596,59 @@
     }
 
     /**
+     * Adds a stream item to a raw contact. The stream item is usually obtained
+     * from the server you are syncing with, but we create it here locally as an
+     * example.
+     *
+     * @param context the Authenticator Activity context
+     * @param rawContactId the raw contact ID that the stream item is associated with
+     * @param accountName the account name of the sync adapter
+     * @param accountType the account type of the sync adapter
+     * @param text the text of the stream item
+     * @param comments the comments for the stream item, such as where the stream item came from
+     * @param batchOperation allow us to batch together multiple operations
+     */
+    private static void addContactStreamItem(Context context, long rawContactId,
+        String accountName, String accountType, String text, String comments,
+        BatchOperation batchOperation) {
+
+        final ContentValues values = new ContentValues();
+        final ContentResolver resolver = context.getContentResolver();
+        if (rawContactId > 0){
+            values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
+            values.put(StreamItems.TEXT, text);
+            values.put(StreamItems.TIMESTAMP, System.currentTimeMillis());
+            values.put(StreamItems.COMMENTS, comments);
+            values.put(StreamItems.ACCOUNT_NAME, accountName);
+            values.put(StreamItems.ACCOUNT_TYPE, accountType);
+
+            batchOperation.add(ContactOperations.newInsertCpo(
+                    StreamItems.CONTENT_URI, false, true).withValues(values).build());
+
+    }
+
+    private static void addStreamItemPhoto(Context context, ContentResolver
+        resolver, long streamItemId, String accountName, String accountType,
+        BatchOperation batchOperation){
+
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
+                R.raw.img1);
+        bitmap.compress(Bitmap.CompressFormat.JPEG, 30, stream);
+        byte[] photoData = stream.toByteArray();
+
+        final ContentValues values = new ContentValues();
+        values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
+        values.put(StreamItemPhotos.SORT_INDEX, 1);
+        values.put(StreamItemPhotos.PHOTO, photoData);
+        values.put(StreamItems.ACCOUNT_NAME, accountName);
+        values.put(StreamItems.ACCOUNT_TYPE, accountType);
+
+        batchOperation.add(ContactOperations.newInsertCpo(
+                StreamItems.CONTENT_PHOTO_URI, false, true).withValues(values).build());
+    }
+
+    /**
      * Clear the local system 'dirty' flag for a contact.
      *
      * @param context the Authenticator Activity context
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 0f570cd..eeb0830 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -115,8 +115,21 @@
             // 2-way contact sync providers - it's more likely that one-way
             // sync providers (IM clients, social networking apps, etc) would
             // use this feature.
+
             ContactManager.updateStatusMessages(mContext, updatedContacts);
 
+            // This is a demo of how you can add stream items for contacts on
+            // the client. This probably won't apply to
+            // 2-way contact sync providers - it's more likely that one-way
+            // sync providers (IM clients, social networking apps, etc) would
+            // use this feature. This is only supported in ICS MR1 or above.
+
+            if (Build.VERSION.SDK_INT >=
+                    Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+                ContactManager.addStreamItems(mContext, updatedContacts,
+                    account.name, account.type);
+            }
+
             // Save off the new sync marker. On our next sync, we only want to receive
             // contacts that have changed since this sync...
             setServerSyncMarker(account, newSyncState);