Add synthetic columns to voicemail table.

- Since our voicemail table supports getInputStream and getOutputStream
  we should also support the columns for DISPLAY_NAME and SIZE, since
  these are expected to exist for helping other apps share files -
  attaching to an email in GMail for example.
- Uses an SQL hack to combine a suitably localized string with the
  number column for the display name.

Bug: 5066115
Change-Id: I48a08ade2a3a2a28a1d3e3415ec27dd956056d44
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6882249..7c8c76b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,4 +45,11 @@
          they want to allow the application to do this. [CHAR LIMIT=NONE] -->
     <string name="read_write_all_voicemail_description">Allows the application to store and retrieve
         all voicemails that this device can access.</string>
+
+    <!-- The prefix string before the number used for the display name for the voicemail table.
+         Because of the way this is combined in SQL we can't allow a generic format string.
+         The resulting string will be this string with the number appended to the end.
+         Note that the trailing space is important, and that to achieve it we have to wrap the
+         string in double quotes. -->
+    <string name="voicemail_from_column">"Voicemail from "</string>
 </resources>
diff --git a/src/com/android/providers/contacts/VoicemailContentTable.java b/src/com/android/providers/contacts/VoicemailContentTable.java
index 92d833d..ee5da3f 100644
--- a/src/com/android/providers/contacts/VoicemailContentTable.java
+++ b/src/com/android/providers/contacts/VoicemailContentTable.java
@@ -26,12 +26,14 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.provider.CallLog.Calls;
+import android.provider.OpenableColumns;
 import android.provider.VoicemailContract.Voicemails;
 import android.util.Log;
 
@@ -44,20 +46,7 @@
  */
 public class VoicemailContentTable implements VoicemailTable.Delegate {
     private static final String TAG = "VoicemailContentProvider";
-    // Voicemail projection map
-    private static final ProjectionMap sVoicemailProjectionMap = new ProjectionMap.Builder()
-            .add(Voicemails._ID)
-            .add(Voicemails.NUMBER)
-            .add(Voicemails.DATE)
-            .add(Voicemails.DURATION)
-            .add(Voicemails.IS_READ)
-            .add(Voicemails.STATE)
-            .add(Voicemails.SOURCE_DATA)
-            .add(Voicemails.SOURCE_PACKAGE)
-            .add(Voicemails.HAS_CONTENT)
-            .add(Voicemails.MIME_TYPE)
-            .add(Voicemails._DATA)
-            .build();
+    private final ProjectionMap mVoicemailProjectionMap;
 
     /** The private directory in which to store the data associated with the voicemail. */
     private static final String DATA_DIRECTORY = "voicemail-data";
@@ -76,11 +65,37 @@
         mContext = context;
         mDbHelper = dbHelper;
         mDelegateHelper = contentProviderHelper;
+        mVoicemailProjectionMap = new ProjectionMap.Builder()
+                .add(Voicemails._ID)
+                .add(Voicemails.NUMBER)
+                .add(Voicemails.DATE)
+                .add(Voicemails.DURATION)
+                .add(Voicemails.IS_READ)
+                .add(Voicemails.STATE)
+                .add(Voicemails.SOURCE_DATA)
+                .add(Voicemails.SOURCE_PACKAGE)
+                .add(Voicemails.HAS_CONTENT)
+                .add(Voicemails.MIME_TYPE)
+                .add(Voicemails._DATA)
+                .add(OpenableColumns.DISPLAY_NAME, createDisplayName(context))
+                .add(OpenableColumns.SIZE, "NULL")
+                .build();
+    }
+
+    /**
+     * Calculate a suitable value for the display name column.
+     * <p>
+     * This is a bit of a hack, it uses a suitably localized string and uses SQL to combine this
+     * with the number column.
+     */
+    private static String createDisplayName(Context context) {
+        String prefix = context.getString(R.string.voicemail_from_column);
+        return DatabaseUtils.sqlEscapeString(prefix) + " || " + Voicemails.NUMBER;
     }
 
     @Override
     public Uri insert(UriData uriData, ContentValues values) {
-        checkForSupportedColumns(sVoicemailProjectionMap, values);
+        checkForSupportedColumns(mVoicemailProjectionMap, values);
         ContentValues copiedValues = new ContentValues(values);
         checkInsertSupported(uriData);
         mDelegateHelper.checkAndAddSourcePackageIntoValues(uriData, copiedValues);
@@ -165,7 +180,7 @@
             String[] selectionArgs, String sortOrder) {
         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
         qb.setTables(mTableName);
-        qb.setProjectionMap(sVoicemailProjectionMap);
+        qb.setProjectionMap(mVoicemailProjectionMap);
         qb.setStrict(true);
 
         String combinedClause = concatenateClauses(selection, uriData.getWhereClause(),
@@ -181,7 +196,7 @@
     @Override
     public int update(UriData uriData, ContentValues values, String selection,
             String[] selectionArgs) {
-        checkForSupportedColumns(sVoicemailProjectionMap, values);
+        checkForSupportedColumns(mVoicemailProjectionMap, values);
         checkUpdateSupported(uriData);
         final SQLiteDatabase db = mDbHelper.getWritableDatabase();
         // TODO: This implementation does not allow bulk update because it only accepts