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