1/* 2* Copyright (C) 2014 Samsung System LSI 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15package com.android.bluetooth.map; 16 17import android.annotation.TargetApi; 18import android.content.ContentProvider; 19import android.content.ContentValues; 20import android.database.Cursor; 21import android.net.Uri; 22import android.os.Bundle; 23import android.os.ParcelFileDescriptor; 24import android.provider.Telephony.Mms; 25import android.util.Log; 26 27import com.google.android.mms.MmsException; 28import com.google.android.mms.pdu.GenericPdu; 29import com.google.android.mms.pdu.PduComposer; 30import com.google.android.mms.pdu.PduPersister; 31 32import java.io.FileNotFoundException; 33import java.io.FileOutputStream; 34import java.io.IOException; 35 36/** 37 * Provider to let the MMS subsystem read data from it own database from another process. 38 * Workaround for missing access to sendStoredMessage(). 39 */ 40@TargetApi(19) 41public class MmsFileProvider extends ContentProvider { 42 static final String TAG = "BluetoothMmsFileProvider"; 43 private PipeWriter mPipeWriter = new PipeWriter(); 44 45 /*package*/ 46 static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.map.MmsFileProvider"); 47 48 @Override 49 public boolean onCreate() { 50 return true; 51 } 52 53 @Override 54 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 55 String sortOrder) { 56 // Don't support queries. 57 return null; 58 } 59 60 @Override 61 public Uri insert(Uri uri, ContentValues values) { 62 // Don't support inserts. 63 return null; 64 } 65 66 @Override 67 public int delete(Uri uri, String selection, String[] selectionArgs) { 68 // Don't support deletes. 69 return 0; 70 } 71 72 @Override 73 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 74 // Don't support updates. 75 return 0; 76 } 77 78 @Override 79 public String getType(Uri uri) { 80 // For this sample, assume all files have no type. 81 return null; 82 } 83 84 @Override 85 public ParcelFileDescriptor openFile(Uri uri, String fileMode) throws FileNotFoundException { 86 String idStr = uri.getLastPathSegment(); 87 if(idStr == null) { 88 throw new FileNotFoundException("Unable to extract message handle from: " + uri); 89 } 90 try { 91 long id = Long.parseLong(idStr); 92 } catch (NumberFormatException e) { 93 Log.w(TAG,e); 94 throw new FileNotFoundException("Unable to extract message handle from: " + uri); 95 } 96 Uri messageUri = Mms.CONTENT_URI.buildUpon().appendEncodedPath(idStr).build(); 97 98 return openPipeHelper (messageUri, null, null, null, mPipeWriter); 99 } 100 101 102 public class PipeWriter implements PipeDataWriter<Cursor> { 103 /** 104 * Generate a message based on the cursor, and write the encoded data to the stream. 105 */ 106 107 public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, 108 Bundle opts, Cursor c) { 109 if (BluetoothMapService.DEBUG) Log.d(TAG, "writeDataToPipe(): uri=" + uri.toString() + 110 " - getLastPathSegment() = " + uri.getLastPathSegment()); 111 112 FileOutputStream fout = null; 113 GenericPdu pdu = null; 114 PduPersister pduPersister = null; 115 116 try { 117 fout = new FileOutputStream(output.getFileDescriptor()); 118 pduPersister = PduPersister.getPduPersister(getContext()); 119 pdu = pduPersister.load(uri); 120 byte[] bytes = (new PduComposer(getContext(), pdu)).make(); 121 fout.write(bytes); 122 123 } catch (IOException e) { 124 Log.w(TAG, e); 125 /* TODO: How to signal the error to the calling entity? Had expected writeDataToPipe 126 * to throw IOException? 127 */ 128 } catch (MmsException e) { 129 Log.w(TAG, e); 130 /* TODO: How to signal the error to the calling entity? Had expected writeDataToPipe 131 * to throw IOException? 132 */ 133 } finally { 134 if(pduPersister != null) pduPersister.release(); 135 try { 136 fout.flush(); 137 } catch (IOException e) { 138 Log.w(TAG, "IOException: ", e); 139 } 140 try { 141 fout.close(); 142 } catch (IOException e) { 143 Log.w(TAG, "IOException: ", e); 144 } 145 } 146 } 147 } 148 149 150} 151