1326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde/* 2326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Copyright (C) 2013 The Android Open Source Project 3326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 4326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Licensed under the Apache License, Version 2.0 (the "License"); 5326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * you may not use this file except in compliance with the License. 6326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * You may obtain a copy of the License at 7326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 8326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * http://www.apache.org/licenses/LICENSE-2.0 9326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 10326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Unless required by applicable law or agreed to in writing, software 11326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * distributed under the License is distributed on an "AS IS" BASIS, 12326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * See the License for the specific language governing permissions and 14326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * limitations under the License. 15326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 16326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 17326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondepackage com.android.bluetooth.mapapi; 18326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 19326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.ContentProvider; 20326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.ContentResolver; 21326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.ContentValues; 22326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.Context; 23326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.UriMatcher; 24326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.pm.ProviderInfo; 25326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.database.Cursor; 26326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.net.Uri; 27326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.AsyncTask; 28326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.Binder; 29326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.Bundle; 30326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.ParcelFileDescriptor; 31326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.util.Log; 32326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 33326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.io.FileInputStream; 34326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.io.FileNotFoundException; 35326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.io.FileOutputStream; 36326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.io.IOException; 37326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.List; 38326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.Map; 39326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.Map.Entry; 40326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.Set; 41326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 42326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde/** 43326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * A base implementation of the BluetoothMapEmailContract. 44326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * A base class for a ContentProvider that allows access to Email messages from a Bluetooth 45326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * device through the Message Access Profile. 46326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 47326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondepublic abstract class BluetoothMapEmailProvider extends ContentProvider { 48326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 49326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final String TAG = "BluetoothMapEmailProvider"; 50326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final boolean D = true; 51326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 52326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int MATCH_ACCOUNT = 1; 53326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int MATCH_MESSAGE = 2; 54326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int MATCH_FOLDER = 3; 55326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 56326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected ContentResolver mResolver; 57326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 58326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private Uri CONTENT_URI = null; 59326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mAuthority; 60326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private UriMatcher mMatcher; 61326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 62326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 63326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private PipeReader mPipeReader = new PipeReader(); 64326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private PipeWriter mPipeWriter = new PipeWriter(); 65326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 66326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 67326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Write the content of a message to a stream as MIME encoded RFC-2822 data. 68326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account to which the message belong 69326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param messageId the ID of the message to write to the stream 70326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param includeAttachment true if attachments should be included 71326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param download true if any missing part of the message shall be downloaded 72326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * before written to the stream. The download flag will determine 73326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * whether or not attachments shall be downloaded or only the message content. 74326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param out the FileOurputStream to write to. 75326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @throws IOException 76326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 77326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected void WriteMessageToStream(long accountId, long messageId, 78326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean includeAttachment, boolean download, FileOutputStream out) 79326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throws IOException; 80326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 81326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 82326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the CONTENT_URI exposed. This will be used to send out notifications. 83326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 84326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected Uri getContentUri(); 85326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 86326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 87326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Implementation is provided by the parent class. 88326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 89326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 90326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void attachInfo(Context context, ProviderInfo info) { 91326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAuthority = info.authority; 92326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 93326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMatcher = new UriMatcher(UriMatcher.NO_MATCH); 94326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMatcher.addURI(mAuthority, BluetoothMapContract.TABLE_ACCOUNT, MATCH_ACCOUNT); 95326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMatcher.addURI(mAuthority, "#/"+BluetoothMapContract.TABLE_FOLDER, MATCH_FOLDER); 96326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMatcher.addURI(mAuthority, "#/"+BluetoothMapContract.TABLE_MESSAGE, MATCH_MESSAGE); 97326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 98326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Sanity check our setup 99326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (!info.exported) { 100326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new SecurityException("Provider must be exported"); 101326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 102326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Enforce correct permissions are used 103326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (!android.Manifest.permission.BLUETOOTH_MAP.equals(info.writePermission)){ 104326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new SecurityException("Provider must be protected by " + 105326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde android.Manifest.permission.BLUETOOTH_MAP); 106326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 107326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mResolver = context.getContentResolver(); 108326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde super.attachInfo(context, info); 109326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 110326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 111326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 112326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 113326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Interface to write a stream of data to a pipe. Use with 114326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * {@link ContentProvider#openPipeHelper}. 115326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 116326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public interface PipeDataReader<T> { 117326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 118326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Called from a background thread to stream data from a pipe. 119326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Note that the pipe is blocking, so this thread can block on 120326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * reads for an arbitrary amount of time if the client is slow 121326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * at writing. 122326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 123326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param input The pipe where data should be read. This will be 124326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * closed for you upon returning from this function. 125326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param uri The URI whose data is to be written. 126326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param mimeType The desired type of data to be written. 127326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param opts Options supplied by caller. 128326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param args Your own custom arguments. 129326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 130326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void readDataFromPipe(ParcelFileDescriptor input, Uri uri, String mimeType, 131326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Bundle opts, T args); 132326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 133326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 134326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public class PipeReader implements PipeDataReader<Cursor> { 135326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 136326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Read the data from the pipe and generate a message. 137326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Use the message to do an update of the message specified by the URI. 138326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 139326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 140326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void readDataFromPipe(ParcelFileDescriptor input, Uri uri, 141326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String mimeType, Bundle opts, Cursor args) { 142326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.v(TAG, "readDataFromPipe(): uri=" + uri.toString()); 143326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde FileInputStream fIn = null; 144326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 145326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fIn = new FileInputStream(input.getFileDescriptor()); 146326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long messageId = Long.valueOf(uri.getLastPathSegment()); 147326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long accountId = Long.valueOf(getAccountId(uri)); 148326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde UpdateMimeMessageFromStream(fIn, accountId, messageId); 149326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 150326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG,"IOException: ", e); 151326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* TODO: How to signal the error to the calling entity? Had expected readDataFromPipe 152326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * to throw IOException? 153326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 154326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 155326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 156326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(fIn != null) 157326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fIn.close(); 158326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 159326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG,e); 160326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 161326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 162326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 163326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 164326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 165326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 166326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Read a MIME encoded RFC-2822 fileStream and update the message content. 167326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * The Date and/or From headers may not be present in the MIME encoded 168326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * message, and this function shall add appropriate values if the headers 169326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * are missing. From should be set to the owner of the account. 170326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 171326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param input the file stream to read data from 172326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the accountId 173326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param messageId ID of the message to update 174326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 175326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected void UpdateMimeMessageFromStream(FileInputStream input, long accountId, 176326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long messageId) throws IOException; 177326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 178326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public class PipeWriter implements PipeDataWriter<Cursor> { 179326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 180326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Generate a message based on the cursor, and write the encoded data to the stream. 181326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 182326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 183326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, 184326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Bundle opts, Cursor c) { 185326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "writeDataToPipe(): uri=" + uri.toString() + 186326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde " - getLastPathSegment() = " + uri.getLastPathSegment()); 187326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 188326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde FileOutputStream fout = null; 189326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 190326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 191326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fout = new FileOutputStream(output.getFileDescriptor()); 192326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 193326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean includeAttachments = true; 194326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean download = false; 195326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde List<String> segments = uri.getPathSegments(); 196326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long messageId = Long.parseLong(segments.get(2)); 197326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long accountId = Long.parseLong(getAccountId(uri)); 198326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(segments.size() >= 4) { 199326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String format = segments.get(3); 200326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(format.equalsIgnoreCase(BluetoothMapContract.FILE_MSG_NO_ATTACHMENTS)) { 201326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde includeAttachments = false; 202326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else if(format.equalsIgnoreCase(BluetoothMapContract.FILE_MSG_DOWNLOAD_NO_ATTACHMENTS)) { 203326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde includeAttachments = false; 204326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde download = true; 205326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else if(format.equalsIgnoreCase(BluetoothMapContract.FILE_MSG_DOWNLOAD)) { 206326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde download = true; 207326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 208326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 209326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 210326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde WriteMessageToStream(accountId, messageId, includeAttachments, download, fout); 211326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 212326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, e); 213326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* TODO: How to signal the error to the calling entity? Had expected writeDataToPipe 214326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * to throw IOException? 215326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 216326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 217326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 218326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fout.flush(); 219326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 220326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "IOException: ", e); 221326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 222326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 223326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fout.close(); 224326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 225326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "IOException: ", e); 226326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 227326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 228326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 229326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 230326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 231326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 232326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This function shall be called when any Account database content have changed 233326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * to Notify any attached observers. 234326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account that changed. Null is a valid value, 235326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * if accountId is unknown or multiple accounts changed. 236326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 237326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected void onAccountChanged(String accountId) { 238326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Uri newUri = null; 239326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 240326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mAuthority == null){ 241326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return; 242326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 243326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(accountId == null){ 244326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newUri = BluetoothMapContract.buildAccountUri(mAuthority); 245326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 246326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newUri = BluetoothMapContract.buildAccountUriwithId(mAuthority, accountId); 247326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 248326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D) Log.d(TAG,"onAccountChanged() accountId = " + accountId + " URI: " + newUri); 249326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mResolver.notifyChange(newUri, null); 250326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 251326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 252326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 253326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This function shall be called when any Message database content have changed 254326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * to notify any attached observers. 255326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId Null is a valid value, if accountId is unknown, but 256326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * recommended for increased performance. 257326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param messageId Null is a valid value, if multiple messages changed or the 258326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * messageId is unknown, but recommended for increased performance. 259326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 260326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected void onMessageChanged(String accountId, String messageId) { 261326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Uri newUri = null; 262326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 263326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mAuthority == null){ 264326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return; 265326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 266326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 267326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(accountId == null){ 268326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newUri = BluetoothMapContract.buildMessageUri(mAuthority); 269326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 270326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(messageId == null) 271326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde { 272326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newUri = BluetoothMapContract.buildMessageUri(mAuthority,accountId); 273326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 274326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newUri = BluetoothMapContract.buildMessageUriWithId(mAuthority,accountId, messageId); 275326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 276326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 277326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D) Log.d(TAG,"onMessageChanged() accountId = " + accountId + " messageId = " + messageId + " URI: " + newUri); 278326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mResolver.notifyChange(newUri, null); 279326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 280326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 281326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 282326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Not used, this is just a dummy implementation. 283326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 284326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 285326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public String getType(Uri uri) { 286326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return "Email"; 287326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 288326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 289326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 290326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Open a file descriptor to a message. 291326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Two modes supported for read: With and without attachments. 292326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * One mode exist for write and the actual content will be with or without 293326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * attachments. 294326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 295326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Mode will be "r" or "w". 296326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 297326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * URI format: 298326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * The URI scheme is as follows. 299326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * For messages with attachments: 300326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * content://com.android.mail.bluetoothprovider/Messages/msgId# 301326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 302326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * For messages without attachments: 303326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * content://com.android.mail.bluetoothprovider/Messages/msgId#/NO_ATTACHMENTS 304326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 305326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * UPDATE: For write. 306326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * First create a message in the DB using insert into the message DB 307326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Then open a file handle to the #id 308326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * write the data to a stream created from the fileHandle. 309326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 310326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param uri the URI to open. ../Messages/#id 311326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param mode the mode to use. The following modes exist: - UPDATE do not work - use URI 312326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - "read_with_attachments" - to read an e-mail including any attachments 313326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - "read_no_attachments" - to read an e-mail excluding any attachments 314326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - "write" - to add a mime encoded message to the database. This write 315326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * should not trigger the message to be send. 316326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the ParcelFileDescriptor 317326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @throws FileNotFoundException 318326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 319326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 320326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 321326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 322326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D)Log.d(TAG, "openFile(): uri=" + uri.toString() + " - getLastPathSegment() = " + 323326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde uri.getLastPathSegment()); 324326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 325326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* To be able to do abstraction of the file IO, we simply ignore the URI at this 326326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * point and let the read/write function implementations parse the URI. */ 327326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mode.equals("w")) { 328326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return openInversePipeHelper(uri, null, null, null, mPipeReader); 329326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 330326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return openPipeHelper (uri, null, null, null, mPipeWriter); 331326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 332326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 333326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG,e); 334326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 335326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 336326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 337326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 338326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 339326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 340326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 341326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * A helper function for implementing {@link #openFile}, for 342326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * creating a data pipe and background thread allowing you to stream 343326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * data back from the client. This function returns a new 344326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * ParcelFileDescriptor that should be returned to the caller (the caller 345326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * is responsible for closing it). 346326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 347326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param uri The URI whose data is to be written. 348326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param mimeType The desired type of data to be written. 349326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param opts Options supplied by caller. 350326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param args Your own custom arguments. 351326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param func Interface implementing the function that will actually 352326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * stream the data. 353326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return Returns a new ParcelFileDescriptor holding the read side of 354326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * the pipe. This should be returned to the caller for reading; the caller 355326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * is responsible for closing it when done. 356326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 357326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private <T> ParcelFileDescriptor openInversePipeHelper(final Uri uri, final String mimeType, 358326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde final Bundle opts, final T args, final PipeDataReader<T> func) 359326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throws FileNotFoundException { 360326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 361326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 362326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 363326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() { 364326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 365326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected Object doInBackground(Object... params) { 366326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde func.readDataFromPipe(fds[0], uri, mimeType, opts, args); 367326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 368326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde fds[0].close(); 369326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 370326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "Failure closing pipe", e); 371326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 372326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 373326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 374326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde }; 375326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null); 376326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 377326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return fds[1]; 378326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 379326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new FileNotFoundException("failure making pipe"); 380326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 381326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 382326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 383326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 384326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * The MAP specification states that a delete request from MAP client is a folder shift to the 385326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 'deleted' folder. 386326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Only use case of delete() is when transparency is requested for push messages, then 387326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * message should not remain in sent folder and therefore must be deleted 388326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 389326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 390326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public int delete(Uri uri, String where, String[] selectionArgs) { 391326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "delete(): uri=" + uri.toString() ); 392326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde int result = 0; 393326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 394326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String table = uri.getPathSegments().get(1); 395326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table == null) 396326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Table missing in URI"); 397326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // the id of the entry to be deleted from the database 398326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String messageId = uri.getLastPathSegment(); 399326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (messageId == null) 400326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Message ID missing in update values!"); 401326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 402326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 403326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String accountId = getAccountId(uri); 404326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (accountId == null) 405326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Account ID missing in update values!"); 406326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 407326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 408326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 409326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table.equals(BluetoothMapContract.TABLE_MESSAGE)) { 410326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return deleteMessage(accountId, messageId); 411326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 412326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.w(TAG, "Unknown table name: " + table); 413326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return result; 414326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 415326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 416326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 417326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 418326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 419326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 420326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 421326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This function deletes a message. 422326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the Account 423326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param messageId the ID of the message to delete. 424326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the number of messages deleted - 0 if the message was not found. 425326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 426326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected int deleteMessage(String accountId, String messageId); 427326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 428326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 429326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Insert is used to add new messages to the data base. 430326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Insert message approach: 431326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - Insert an empty message to get an _id with only a folder_id 432326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - Open the _id for write 433326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - Write the message content 434326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * (When the writer completes, this provider should do an update of the message) 435326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 436326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 437326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public Uri insert(Uri uri, ContentValues values) { 438326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String table = uri.getLastPathSegment(); 439326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table == null){ 440326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Table missing in URI"); 441326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 442326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String accountId = getAccountId(uri); 443326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Long folderId = values.getAsLong(BluetoothMapContract.MessageColumns.FOLDER_ID); 444326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(folderId == null) { 445326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("FolderId missing in ContentValues"); 446326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 447326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 448326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String id; // the id of the entry inserted into the database 449326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 450326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.d(TAG, "insert(): uri=" + uri.toString() + " - getLastPathSegment() = " + 451326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde uri.getLastPathSegment()); 452326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 453326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table.equals(BluetoothMapContract.TABLE_MESSAGE)) { 454326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde id = insertMessage(accountId, folderId.toString()); 455326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D) Log.i(TAG, "insert() ID: " + id); 456326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return Uri.parse(uri.toString() + "/" + id); 457326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 458326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "Unknown table name: " + table); 459326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 460326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 461326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 462326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 463326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 464326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 465326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 466326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 467326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 468326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Inserts an empty message into the Message data base in the specified folder. 469326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This is done before the actual message content is written by fileIO. 470326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account 471326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param folderId the ID of the folder to create a new message in. 472326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the message id as a string 473326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 474326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected String insertMessage(String accountId, String folderId); 475326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 476326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 477326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Utility function to build a projection based on a projectionMap. 478326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 479326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * "btColumnName" -> "emailColumnName as btColumnName" for each entry. 480326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * 481326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This supports SQL statements in the emailColumnName entry. 482326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param projection 483326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param projectionMap <btColumnName, emailColumnName> 484326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the converted projection 485326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 486326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde protected String[] convertProjection(String[] projection, Map<String,String> projectionMap) { 487326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String[] newProjection = new String[projection.length]; 488326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for(int i = 0; i < projection.length; i++) { 489326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde newProjection[i] = projectionMap.get(projection[i]) + " as " + projection[i]; 490326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 491326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return newProjection; 492326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 493326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 494326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 495326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This query needs to map from the data used in the e-mail client to BluetoothMapContract type of data. 496326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 497326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 498326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 499326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String sortOrder) { 500326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 501326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 502326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String accountId = null; 503326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde switch (mMatcher.match(uri)) { 504326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde case MATCH_ACCOUNT: 505326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return queryAccount(projection, selection, selectionArgs, sortOrder); 506326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde case MATCH_FOLDER: 507326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde accountId = getAccountId(uri); 508326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return queryFolder(accountId, projection, selection, selectionArgs, sortOrder); 509326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde case MATCH_MESSAGE: 510326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde accountId = getAccountId(uri); 511326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return queryMessage(accountId, projection, selection, selectionArgs, sortOrder); 512326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde default: 513326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new UnsupportedOperationException("Unsupported Uri " + uri); 514326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 515326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 516326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 517326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 518326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 519326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 520326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 521326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Query account information. 522326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * This function shall return only exposable e-mail accounts. Hence shall not 523326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * return accounts that has policies suggesting not to be shared them. 524326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param projection 525326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selection 526326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selectionArgs 527326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param sortOrder 528326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return a cursor to the accounts that are subject to exposure over BT. 529326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 530326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected Cursor queryAccount(String[] projection, String selection, String[] selectionArgs, 531326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String sortOrder); 532326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 533326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 534326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Filter out the non usable folders and ensure to name the mandatory folders 535326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * inbox, outbox, sent, deleted and draft. 536326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId 537326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param projection 538326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selection 539326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selectionArgs 540326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param sortOrder 541326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return 542326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 543326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected Cursor queryFolder(String accountId, String[] projection, String selection, String[] selectionArgs, 544326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String sortOrder); 545326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 546326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * For the message table the selection (where clause) can only include the following columns: 547326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * date: less than, greater than and equals 548326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * flagRead: = 1 or = 0 549326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * flagPriority: = 1 or = 0 550326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * folder_id: the ID of the folder only equals 551326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * toList: partial name/address search 552326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * ccList: partial name/address search 553326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * bccList: partial name/address search 554326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * fromList: partial name/address search 555326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Additionally the COUNT and OFFSET shall be supported. 556326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account 557326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param projection 558326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selection 559326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param selectionArgs 560326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param sortOrder 561326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return a cursor to query result 562326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 563326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected Cursor queryMessage(String accountId, String[] projection, String selection, String[] selectionArgs, 564326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String sortOrder); 565326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 566326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 567326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * update() 568326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Messages can be modified in the following cases: 569326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - the folder_key of a message - hence the message can be moved to a new folder, 570326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * but the content cannot be modified. 571326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * - the FLAG_READ state can be changed. 572326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * The selection statement will always be selection of a message ID, when updating a message, 573326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * hence this function will be called multiple times if multiple messages must be updated 574326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * due to the nature of the Bluetooth Message Access profile. 575326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 576326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 577326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 578326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 579326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String table = uri.getLastPathSegment(); 580326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table == null){ 581326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Table missing in URI"); 582326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 583326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(selection != null) { 584326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("selection shall not be used, ContentValues shall contain the data"); 585326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 586326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 587326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 588326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D)Log.w(TAG, "update(): uri=" + uri.toString() + " - getLastPathSegment() = " + 589326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde uri.getLastPathSegment()); 590326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 591326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(table.equals(BluetoothMapContract.TABLE_ACCOUNT)) { 592326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String accountId = values.getAsString(BluetoothMapContract.AccountColumns._ID); 593326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(accountId == null) { 594326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Account ID missing in update values!"); 595326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 596326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Integer exposeFlag = values.getAsInteger(BluetoothMapContract.AccountColumns.FLAG_EXPOSE); 597326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(exposeFlag == null){ 598326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Expose flag missing in update values!"); 599326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 600326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return updateAccount(accountId, exposeFlag); 601326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else if(table.equals(BluetoothMapContract.TABLE_FOLDER)) { 602326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return 0; // We do not support changing folders 603326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else if(table.equals(BluetoothMapContract.TABLE_MESSAGE)) { 604326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String accountId = getAccountId(uri); 605326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Long messageId = values.getAsLong(BluetoothMapContract.MessageColumns._ID); 606326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(messageId == null) { 607326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("Message ID missing in update values!"); 608326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 609326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Long folderId = values.getAsLong(BluetoothMapContract.MessageColumns.FOLDER_ID); 610326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Boolean flagRead = values.getAsBoolean(BluetoothMapContract.MessageColumns.FLAG_READ); 611326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return updateMessage(accountId, messageId, folderId, flagRead); 612326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 613326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D)Log.w(TAG, "Unknown table name: " + table); 614326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return 0; 615326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 616326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 617326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 618326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 619326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 620326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 621326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 622326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Update an entry in the account table. Only the expose flag will be 623326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * changed through this interface. 624326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account to change. 625326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param flagExpose the updated value. 626326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return the number of entries changed - 0 if account not found or value cannot be changed. 627326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 628326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected int updateAccount(String accountId, int flagExpose); 629326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 630326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 631326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Update an entry in the message table. 632326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId ID of the account to which the messageId relates 633326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param messageId the ID of the message to update 634326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param folderId the new folder ID value to set - ignore if null. 635326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param flagRead the new flagRead value to set - ignore if null. 636326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return 637326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 638326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected int updateMessage(String accountId, Long messageId, Long folderId, Boolean flagRead); 639326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 640326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 641326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 642326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public Bundle call(String method, String arg, Bundle extras) { 643326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long callingId = Binder.clearCallingIdentity(); 644326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D)Log.d(TAG, "call(): method=" + method + " arg=" + arg + "ThreadId: " + Thread.currentThread().getId()); 645326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 646326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 647326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(method.equals(BluetoothMapContract.METHOD_UPDATE_FOLDER)) { 648326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long accountId = extras.getLong(BluetoothMapContract.EXTRA_UPDATE_ACCOUNT_ID, -1); 649326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(accountId == -1) { 650326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "No account ID in CALL"); 651326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 652326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 653326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde long folderId = extras.getLong(BluetoothMapContract.EXTRA_UPDATE_FOLDER_ID, -1); 654326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(folderId == -1) { 655326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "No folder ID in CALL"); 656326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 657326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 658326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde int ret = syncFolder(accountId, folderId); 659326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(ret == 0) { 660326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return new Bundle(); 661326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 662326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 663326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 664326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 665326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Binder.restoreCallingIdentity(callingId); 666326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 667326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return null; 668326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 669326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 670326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 671326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Trigger a sync of the specified folder. 672326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param accountId the ID of the account that owns the folder 673326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param folderId the ID of the folder. 674326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return 0 at success 675326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 676326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde abstract protected int syncFolder(long accountId, long folderId); 677326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 678326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 679326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Need this to suppress warning in unit tests. 680326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 681326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 682326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void shutdown() { 683326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Don't call super.shutdown(), which emits a warning... 684326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 685326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 686326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 687326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Extract the BluetoothMapContract.AccountColumns._ID from the given URI. 688326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 689326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public static String getAccountId(Uri uri) { 690326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde final List<String> segments = uri.getPathSegments(); 691326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (segments.size() < 1) { 692326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde throw new IllegalArgumentException("No AccountId pressent in URI: " + uri); 693326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 694326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return segments.get(0); 695326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 696326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde} 697