Loading android/app/AndroidManifest.xml +1 −2 Original line number Diff line number Diff line Loading @@ -82,8 +82,7 @@ android:supportsRtl="true" android:usesCleartextTraffic="false" android:directBootAware="true" android:defaultToDeviceProtectedStorage="true" android:requestLegacyExternalStorage="true"> android:defaultToDeviceProtectedStorage="true"> <uses-library android:name="javax.obex" /> <provider android:name=".opp.BluetoothOppProvider" android:authorities="com.android.bluetooth.opp" Loading android/app/src/com/android/bluetooth/opp/BluetoothOppBatch.java +2 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import android.bluetooth.BluetoothDevice; import android.content.Context; import android.util.Log; import java.io.File; import java.util.ArrayList; /** Loading Loading @@ -148,8 +147,8 @@ public class BluetoothOppBatch { BluetoothOppShareInfo info = mShares.get(i); if (info.mStatus < 200) { if (info.mDirection == BluetoothShare.DIRECTION_INBOUND && info.mFilename != null) { new File(info.mFilename).delete(); if (info.mDirection == BluetoothShare.DIRECTION_INBOUND && info.mUri != null) { mContext.getContentResolver().delete(info.mUri, null, null); } if (V) { Log.v(TAG, "Cancel batch for info " + info.mId); Loading android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java +18 −16 Original line number Diff line number Diff line Loading @@ -48,10 +48,10 @@ import com.android.bluetooth.BluetoothMetricsProto; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.btservice.MetricsLogger; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import javax.obex.HeaderSet; Loading Loading @@ -361,14 +361,16 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler } if (mFileInfo.mFileName != null) { if (mFileInfo.mFileName != null && mFileInfo.mInsertUri != null) { ContentValues updateValues = new ContentValues(); contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); updateValues.put(BluetoothShare._DATA, mFileInfo.mFileName); updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING); updateValues.put(BluetoothShare.URI, mFileInfo.mInsertUri.toString()); mContext.getContentResolver().update(contentUri, updateValues, null, null); mInfo.mUri = mFileInfo.mInsertUri; status = receiveFile(mFileInfo, op); /* * TODO map status to obex response code Loading Loading @@ -403,13 +405,8 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler */ Log.i(TAG, "Rejected incoming request"); if (mFileInfo.mFileName != null) { try { mFileInfo.mOutputStream.close(); } catch (IOException e) { Log.e(TAG, "error close file stream"); } new File(mFileInfo.mFileName).delete(); if (mFileInfo.mInsertUri != null) { mContext.getContentResolver().delete(mFileInfo.mInsertUri, null, null); } // set status as local cancel status = BluetoothShare.STATUS_CANCELED; Loading @@ -430,8 +427,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler * implement receive file */ int status = -1; BufferedOutputStream bos = null; OutputStream os = null; InputStream is = null; boolean error = false; try { Loading @@ -455,7 +451,12 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler long prevPercent = 0; if (!error) { bos = new BufferedOutputStream(fileInfo.mOutputStream, 0x10000); try { os = mContext.getContentResolver().openOutputStream(fileInfo.mInsertUri); } catch (FileNotFoundException e) { Log.e(TAG, "Error when openOutputStream"); error = true; } } if (!error) { Loading @@ -481,7 +482,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler break; } bos.write(b, 0, readLength); os.write(b, 0, readLength); position += readLength; percent = position * 100 / fileInfo.mLength; currentTime = SystemClock.elapsedRealtime(); Loading Loading @@ -536,9 +537,10 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler } } if (bos != null) { if (os != null) { try { bos.close(); os.flush(); os.close(); } catch (IOException e) { Log.e(TAG, "Error when closing stream after send"); } Loading android/app/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java +20 −121 Original line number Diff line number Diff line Loading @@ -38,15 +38,10 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.os.StatFs; import android.os.SystemClock; import android.provider.MediaStore; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Random; /** * This class stores information about a single receiving file. It will only be Loading @@ -67,23 +62,22 @@ public class BluetoothOppReceiveFileInfo { public long mLength; public FileOutputStream mOutputStream; public int mStatus; public String mData; public Uri mInsertUri; public BluetoothOppReceiveFileInfo(String data, long length, int status) { mData = data; mStatus = status; mLength = length; } public BluetoothOppReceiveFileInfo(String filename, long length, FileOutputStream outputStream, int status) { public BluetoothOppReceiveFileInfo(String filename, long length, Uri insertUri, int status) { mFileName = filename; mOutputStream = outputStream; mStatus = status; mInsertUri = insertUri; mLength = length; } Loading Loading @@ -113,39 +107,13 @@ public class BluetoothOppReceiveFileInfo { } } File base = null; StatFs stat = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String root = Environment.getExternalStorageDirectory().getPath(); base = new File(root + Constants.DEFAULT_STORE_SUBDIR); if (!base.isDirectory() && !base.mkdir()) { if (D) { Log.d(Constants.TAG, "Receive File aborted - can't create base directory " + base.getPath()); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } stat = new StatFs(base.getPath()); } else { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (D) { Log.d(Constants.TAG, "Receive File aborted - no external storage"); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_NO_SDCARD); } /* * Check whether there's enough space on the target filesystem to save * the file. Put a bit of margin (in case creating the file grows the * system by a few blocks). */ if (stat.getBlockSizeLong() * (stat.getAvailableBlocksLong() - 4) < length) { if (D) { Log.d(Constants.TAG, "Receive File aborted - not enough free space"); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_SDCARD_FULL); } filename = choosefilename(hint); if (filename == null) { // should not happen. It must be pre-rejected Loading Loading @@ -192,100 +160,31 @@ public class BluetoothOppReceiveFileInfo { } } filename = base.getPath() + File.separator + filename; // Generate a unique filename, create the file, return it. String fullfilename = chooseUniquefilename(filename, extension); String fullfilename = filename + extension; if (!safeCanonicalPath(fullfilename)) { // If this second check fails, then we better reject the transfer return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } if (V) { Log.v(Constants.TAG, "Generated received filename " + fullfilename); } if (fullfilename != null) { try { new FileOutputStream(fullfilename).close(); int index = fullfilename.lastIndexOf('/') + 1; // update display name if (index > 0) { String displayName = fullfilename.substring(index); if (V) { Log.v(Constants.TAG, "New display name " + displayName); } ContentValues updateValues = new ContentValues(); updateValues.put(BluetoothShare.FILENAME_HINT, displayName); context.getContentResolver().update(contentUri, updateValues, null, null); Uri insertUri = null; ContentValues mediaContentValues = new ContentValues(); mediaContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fullfilename); mediaContentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); mediaContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); insertUri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, mediaContentValues); } return new BluetoothOppReceiveFileInfo(fullfilename, length, new FileOutputStream(fullfilename), 0); } catch (IOException e) { if (insertUri == null) { if (D) { Log.e(Constants.TAG, "Error when creating file " + fullfilename); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } } else { return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } } Log.d(Constants.TAG, "file crated, insertUri:" + insertUri.toString()); private static boolean safeCanonicalPath(String uniqueFileName) { try { File receiveFile = new File(uniqueFileName); if (sDesiredStoragePath == null) { sDesiredStoragePath = Environment.getExternalStorageDirectory().getPath() + Constants.DEFAULT_STORE_SUBDIR; } String canonicalPath = receiveFile.getCanonicalPath(); // Check if canonical path is complete - case sensitive-wise if (!canonicalPath.startsWith(sDesiredStoragePath)) { return false; } return true; } catch (IOException ioe) { // If an exception is thrown, there might be something wrong with the file. return false; } } private static String chooseUniquefilename(String filename, String extension) { String fullfilename = filename + extension; if (!new File(fullfilename).exists()) { return fullfilename; } filename = filename + Constants.FILENAME_SEQUENCE_SEPARATOR; /* * This number is used to generate partially randomized filenames to * avoid collisions. It starts at 1. The next 9 iterations increment it * by 1 at a time (up to 10). The next 9 iterations increment it by 1 to * 10 (random) at a time. The next 9 iterations increment it by 1 to 100 * (random) at a time. ... Up to the point where it increases by * 100000000 at a time. (the maximum value that can be reached is * 1000000000) As soon as a number is reached that generates a filename * that doesn't exist, that filename is used. If the filename coming in * is [base].[ext], the generated filenames are [base]-[sequence].[ext]. */ Random rnd = new Random(SystemClock.uptimeMillis()); int sequence = 1; for (int magnitude = 1; magnitude < 1000000000; magnitude *= 10) { for (int iteration = 0; iteration < 9; ++iteration) { fullfilename = filename + sequence + extension; if (!new File(fullfilename).exists()) { return fullfilename; } if (V) { Log.v(Constants.TAG, "file with sequence number " + sequence + " exists"); } sequence += rnd.nextInt(magnitude) + 1; } } return null; return new BluetoothOppReceiveFileInfo(fullfilename, length, insertUri, 0); } private static String choosefilename(String hint) { Loading android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java +4 −5 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ import android.util.Log; import com.android.bluetooth.BluetoothObexTransport; import java.io.File; import java.io.IOException; import javax.obex.ObexTransport; Loading Loading @@ -402,8 +401,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch failReason = mCurrentShare.mStatus; } if (mCurrentShare.mDirection == BluetoothShare.DIRECTION_INBOUND && mCurrentShare.mFilename != null) { new File(mCurrentShare.mFilename).delete(); && mCurrentShare.mUri != null) { mContext.getContentResolver().delete(mCurrentShare.mUri, null, null); } } Loading @@ -429,8 +428,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch updateValues.put(BluetoothShare.MIMETYPE, fileInfo.mMimetype); } } else { if (info.mStatus < 200 && info.mFilename != null) { new File(info.mFilename).delete(); if (info.mStatus < 200 && info.mUri != null) { mContext.getContentResolver().delete(info.mUri, null, null); } } mContext.getContentResolver().update(contentUri, updateValues, null, null); Loading Loading
android/app/AndroidManifest.xml +1 −2 Original line number Diff line number Diff line Loading @@ -82,8 +82,7 @@ android:supportsRtl="true" android:usesCleartextTraffic="false" android:directBootAware="true" android:defaultToDeviceProtectedStorage="true" android:requestLegacyExternalStorage="true"> android:defaultToDeviceProtectedStorage="true"> <uses-library android:name="javax.obex" /> <provider android:name=".opp.BluetoothOppProvider" android:authorities="com.android.bluetooth.opp" Loading
android/app/src/com/android/bluetooth/opp/BluetoothOppBatch.java +2 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import android.bluetooth.BluetoothDevice; import android.content.Context; import android.util.Log; import java.io.File; import java.util.ArrayList; /** Loading Loading @@ -148,8 +147,8 @@ public class BluetoothOppBatch { BluetoothOppShareInfo info = mShares.get(i); if (info.mStatus < 200) { if (info.mDirection == BluetoothShare.DIRECTION_INBOUND && info.mFilename != null) { new File(info.mFilename).delete(); if (info.mDirection == BluetoothShare.DIRECTION_INBOUND && info.mUri != null) { mContext.getContentResolver().delete(info.mUri, null, null); } if (V) { Log.v(TAG, "Cancel batch for info " + info.mId); Loading
android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java +18 −16 Original line number Diff line number Diff line Loading @@ -48,10 +48,10 @@ import com.android.bluetooth.BluetoothMetricsProto; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.btservice.MetricsLogger; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import javax.obex.HeaderSet; Loading Loading @@ -361,14 +361,16 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler } if (mFileInfo.mFileName != null) { if (mFileInfo.mFileName != null && mFileInfo.mInsertUri != null) { ContentValues updateValues = new ContentValues(); contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); updateValues.put(BluetoothShare._DATA, mFileInfo.mFileName); updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING); updateValues.put(BluetoothShare.URI, mFileInfo.mInsertUri.toString()); mContext.getContentResolver().update(contentUri, updateValues, null, null); mInfo.mUri = mFileInfo.mInsertUri; status = receiveFile(mFileInfo, op); /* * TODO map status to obex response code Loading Loading @@ -403,13 +405,8 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler */ Log.i(TAG, "Rejected incoming request"); if (mFileInfo.mFileName != null) { try { mFileInfo.mOutputStream.close(); } catch (IOException e) { Log.e(TAG, "error close file stream"); } new File(mFileInfo.mFileName).delete(); if (mFileInfo.mInsertUri != null) { mContext.getContentResolver().delete(mFileInfo.mInsertUri, null, null); } // set status as local cancel status = BluetoothShare.STATUS_CANCELED; Loading @@ -430,8 +427,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler * implement receive file */ int status = -1; BufferedOutputStream bos = null; OutputStream os = null; InputStream is = null; boolean error = false; try { Loading @@ -455,7 +451,12 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler long prevPercent = 0; if (!error) { bos = new BufferedOutputStream(fileInfo.mOutputStream, 0x10000); try { os = mContext.getContentResolver().openOutputStream(fileInfo.mInsertUri); } catch (FileNotFoundException e) { Log.e(TAG, "Error when openOutputStream"); error = true; } } if (!error) { Loading @@ -481,7 +482,7 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler break; } bos.write(b, 0, readLength); os.write(b, 0, readLength); position += readLength; percent = position * 100 / fileInfo.mLength; currentTime = SystemClock.elapsedRealtime(); Loading Loading @@ -536,9 +537,10 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler } } if (bos != null) { if (os != null) { try { bos.close(); os.flush(); os.close(); } catch (IOException e) { Log.e(TAG, "Error when closing stream after send"); } Loading
android/app/src/com/android/bluetooth/opp/BluetoothOppReceiveFileInfo.java +20 −121 Original line number Diff line number Diff line Loading @@ -38,15 +38,10 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.os.StatFs; import android.os.SystemClock; import android.provider.MediaStore; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Random; /** * This class stores information about a single receiving file. It will only be Loading @@ -67,23 +62,22 @@ public class BluetoothOppReceiveFileInfo { public long mLength; public FileOutputStream mOutputStream; public int mStatus; public String mData; public Uri mInsertUri; public BluetoothOppReceiveFileInfo(String data, long length, int status) { mData = data; mStatus = status; mLength = length; } public BluetoothOppReceiveFileInfo(String filename, long length, FileOutputStream outputStream, int status) { public BluetoothOppReceiveFileInfo(String filename, long length, Uri insertUri, int status) { mFileName = filename; mOutputStream = outputStream; mStatus = status; mInsertUri = insertUri; mLength = length; } Loading Loading @@ -113,39 +107,13 @@ public class BluetoothOppReceiveFileInfo { } } File base = null; StatFs stat = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String root = Environment.getExternalStorageDirectory().getPath(); base = new File(root + Constants.DEFAULT_STORE_SUBDIR); if (!base.isDirectory() && !base.mkdir()) { if (D) { Log.d(Constants.TAG, "Receive File aborted - can't create base directory " + base.getPath()); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } stat = new StatFs(base.getPath()); } else { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (D) { Log.d(Constants.TAG, "Receive File aborted - no external storage"); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_NO_SDCARD); } /* * Check whether there's enough space on the target filesystem to save * the file. Put a bit of margin (in case creating the file grows the * system by a few blocks). */ if (stat.getBlockSizeLong() * (stat.getAvailableBlocksLong() - 4) < length) { if (D) { Log.d(Constants.TAG, "Receive File aborted - not enough free space"); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_ERROR_SDCARD_FULL); } filename = choosefilename(hint); if (filename == null) { // should not happen. It must be pre-rejected Loading Loading @@ -192,100 +160,31 @@ public class BluetoothOppReceiveFileInfo { } } filename = base.getPath() + File.separator + filename; // Generate a unique filename, create the file, return it. String fullfilename = chooseUniquefilename(filename, extension); String fullfilename = filename + extension; if (!safeCanonicalPath(fullfilename)) { // If this second check fails, then we better reject the transfer return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } if (V) { Log.v(Constants.TAG, "Generated received filename " + fullfilename); } if (fullfilename != null) { try { new FileOutputStream(fullfilename).close(); int index = fullfilename.lastIndexOf('/') + 1; // update display name if (index > 0) { String displayName = fullfilename.substring(index); if (V) { Log.v(Constants.TAG, "New display name " + displayName); } ContentValues updateValues = new ContentValues(); updateValues.put(BluetoothShare.FILENAME_HINT, displayName); context.getContentResolver().update(contentUri, updateValues, null, null); Uri insertUri = null; ContentValues mediaContentValues = new ContentValues(); mediaContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fullfilename); mediaContentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); mediaContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); insertUri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, mediaContentValues); } return new BluetoothOppReceiveFileInfo(fullfilename, length, new FileOutputStream(fullfilename), 0); } catch (IOException e) { if (insertUri == null) { if (D) { Log.e(Constants.TAG, "Error when creating file " + fullfilename); } return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } } else { return new BluetoothOppReceiveFileInfo(BluetoothShare.STATUS_FILE_ERROR); } } Log.d(Constants.TAG, "file crated, insertUri:" + insertUri.toString()); private static boolean safeCanonicalPath(String uniqueFileName) { try { File receiveFile = new File(uniqueFileName); if (sDesiredStoragePath == null) { sDesiredStoragePath = Environment.getExternalStorageDirectory().getPath() + Constants.DEFAULT_STORE_SUBDIR; } String canonicalPath = receiveFile.getCanonicalPath(); // Check if canonical path is complete - case sensitive-wise if (!canonicalPath.startsWith(sDesiredStoragePath)) { return false; } return true; } catch (IOException ioe) { // If an exception is thrown, there might be something wrong with the file. return false; } } private static String chooseUniquefilename(String filename, String extension) { String fullfilename = filename + extension; if (!new File(fullfilename).exists()) { return fullfilename; } filename = filename + Constants.FILENAME_SEQUENCE_SEPARATOR; /* * This number is used to generate partially randomized filenames to * avoid collisions. It starts at 1. The next 9 iterations increment it * by 1 at a time (up to 10). The next 9 iterations increment it by 1 to * 10 (random) at a time. The next 9 iterations increment it by 1 to 100 * (random) at a time. ... Up to the point where it increases by * 100000000 at a time. (the maximum value that can be reached is * 1000000000) As soon as a number is reached that generates a filename * that doesn't exist, that filename is used. If the filename coming in * is [base].[ext], the generated filenames are [base]-[sequence].[ext]. */ Random rnd = new Random(SystemClock.uptimeMillis()); int sequence = 1; for (int magnitude = 1; magnitude < 1000000000; magnitude *= 10) { for (int iteration = 0; iteration < 9; ++iteration) { fullfilename = filename + sequence + extension; if (!new File(fullfilename).exists()) { return fullfilename; } if (V) { Log.v(Constants.TAG, "file with sequence number " + sequence + " exists"); } sequence += rnd.nextInt(magnitude) + 1; } } return null; return new BluetoothOppReceiveFileInfo(fullfilename, length, insertUri, 0); } private static String choosefilename(String hint) { Loading
android/app/src/com/android/bluetooth/opp/BluetoothOppTransfer.java +4 −5 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ import android.util.Log; import com.android.bluetooth.BluetoothObexTransport; import java.io.File; import java.io.IOException; import javax.obex.ObexTransport; Loading Loading @@ -402,8 +401,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch failReason = mCurrentShare.mStatus; } if (mCurrentShare.mDirection == BluetoothShare.DIRECTION_INBOUND && mCurrentShare.mFilename != null) { new File(mCurrentShare.mFilename).delete(); && mCurrentShare.mUri != null) { mContext.getContentResolver().delete(mCurrentShare.mUri, null, null); } } Loading @@ -429,8 +428,8 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch updateValues.put(BluetoothShare.MIMETYPE, fileInfo.mMimetype); } } else { if (info.mStatus < 200 && info.mFilename != null) { new File(info.mFilename).delete(); if (info.mStatus < 200 && info.mUri != null) { mContext.getContentResolver().delete(info.mUri, null, null); } } mContext.getContentResolver().update(contentUri, updateValues, null, null); Loading