1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.provider.cts.media; 18 19 import android.content.ContentValues; 20 import android.content.Context; 21 import android.net.Uri; 22 import android.os.Build; 23 import android.os.ParcelFileDescriptor; 24 import android.provider.MediaStore; 25 import android.provider.MediaStore.DownloadColumns; 26 import android.provider.MediaStore.Downloads; 27 import android.provider.MediaStore.MediaColumns; 28 import android.text.format.DateUtils; 29 30 import androidx.annotation.NonNull; 31 import androidx.annotation.Nullable; 32 import androidx.test.filters.SdkSuppress; 33 34 import org.junit.Test; 35 36 import java.io.FileNotFoundException; 37 import java.io.OutputStream; 38 import java.util.Objects; 39 40 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) 41 public class MediaStoreUtils { 42 @Test testStub()43 public void testStub() { 44 } 45 46 /** 47 * Create a new pending media item using the given parameters. Pending items 48 * are expected to have a short lifetime, and owners should either 49 * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a 50 * pending item within a few hours after first creating it. 51 * 52 * @return token which can be passed to {@link #openPending(Context, Uri)} 53 * to work with this pending item. 54 * @see MediaColumns#IS_PENDING 55 * @see MediaStore#setIncludePending(Uri) 56 * @see MediaStore#createPending(Context, PendingParams) 57 * @removed 58 */ 59 @Deprecated createPending(@onNull Context context, @NonNull PendingParams params)60 public static @NonNull Uri createPending(@NonNull Context context, 61 @NonNull PendingParams params) { 62 return context.getContentResolver().insert(params.insertUri, params.insertValues); 63 } 64 65 /** 66 * Open a pending media item to make progress on it. You can open a pending 67 * item multiple times before finally calling either 68 * {@link PendingSession#publish()} or {@link PendingSession#abandon()}. 69 * 70 * @param uri token which was previously returned from 71 * {@link #createPending(Context, PendingParams)}. 72 * @removed 73 */ 74 @Deprecated openPending(@onNull Context context, @NonNull Uri uri)75 public static @NonNull PendingSession openPending(@NonNull Context context, @NonNull Uri uri) { 76 return new PendingSession(context, uri); 77 } 78 79 /** 80 * Parameters that describe a pending media item. 81 * 82 * @removed 83 */ 84 @Deprecated 85 public static class PendingParams { 86 /** {@hide} */ 87 public final Uri insertUri; 88 /** {@hide} */ 89 public final ContentValues insertValues; 90 91 /** 92 * Create parameters that describe a pending media item. 93 * 94 * @param insertUri the {@code content://} Uri where this pending item 95 * should be inserted when finally published. For example, to 96 * publish an image, use 97 * {@link MediaStore.Images.Media#getContentUri(String)}. 98 */ PendingParams(@onNull Uri insertUri, @NonNull String displayName, @NonNull String mimeType)99 public PendingParams(@NonNull Uri insertUri, @NonNull String displayName, 100 @NonNull String mimeType) { 101 this.insertUri = Objects.requireNonNull(insertUri); 102 final long now = System.currentTimeMillis() / 1000; 103 this.insertValues = new ContentValues(); 104 this.insertValues.put(MediaColumns.DISPLAY_NAME, Objects.requireNonNull(displayName)); 105 this.insertValues.put(MediaColumns.MIME_TYPE, Objects.requireNonNull(mimeType)); 106 this.insertValues.put(MediaColumns.DATE_ADDED, now); 107 this.insertValues.put(MediaColumns.DATE_MODIFIED, now); 108 this.insertValues.put(MediaColumns.IS_PENDING, 1); 109 this.insertValues.put(MediaColumns.DATE_EXPIRES, 110 (System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS) / 1000); 111 } 112 setPath(@ullable String path)113 public void setPath(@Nullable String path) { 114 if (path == null) { 115 this.insertValues.remove(MediaColumns.RELATIVE_PATH); 116 } else { 117 this.insertValues.put(MediaColumns.RELATIVE_PATH, path); 118 } 119 } 120 setIsFavorite(@ullable Boolean isFavorite)121 public void setIsFavorite(@Nullable Boolean isFavorite) { 122 this.insertValues.put(MediaColumns.IS_FAVORITE, isFavorite); 123 } 124 125 /** 126 * Optionally set the Uri from where the file has been downloaded. This is used 127 * for files being added to {@link Downloads} table. 128 * 129 * @see DownloadColumns#DOWNLOAD_URI 130 */ setDownloadUri(@ullable Uri downloadUri)131 public void setDownloadUri(@Nullable Uri downloadUri) { 132 if (downloadUri == null) { 133 this.insertValues.remove(DownloadColumns.DOWNLOAD_URI); 134 } else { 135 this.insertValues.put(DownloadColumns.DOWNLOAD_URI, downloadUri.toString()); 136 } 137 } 138 139 /** 140 * Optionally set the Uri indicating HTTP referer of the file. This is used for 141 * files being added to {@link Downloads} table. 142 * 143 * @see DownloadColumns#REFERER_URI 144 */ setRefererUri(@ullable Uri refererUri)145 public void setRefererUri(@Nullable Uri refererUri) { 146 if (refererUri == null) { 147 this.insertValues.remove(DownloadColumns.REFERER_URI); 148 } else { 149 this.insertValues.put(DownloadColumns.REFERER_URI, refererUri.toString()); 150 } 151 } 152 } 153 154 /** 155 * Session actively working on a pending media item. Pending items are 156 * expected to have a short lifetime, and owners should either 157 * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a 158 * pending item within a few hours after first creating it. 159 * 160 * @removed 161 */ 162 @Deprecated 163 public static class PendingSession implements AutoCloseable { 164 /** {@hide} */ 165 private final Context mContext; 166 /** {@hide} */ 167 private final Uri mUri; 168 169 /** {@hide} */ PendingSession(Context context, Uri uri)170 public PendingSession(Context context, Uri uri) { 171 mContext = Objects.requireNonNull(context); 172 mUri = Objects.requireNonNull(uri); 173 } 174 175 /** 176 * Open the underlying file representing this media item. When a media 177 * item is successfully completed, you should 178 * {@link ParcelFileDescriptor#close()} and then {@link #publish()} it. 179 * 180 * @see #notifyProgress(int) 181 */ open()182 public @NonNull ParcelFileDescriptor open() throws FileNotFoundException { 183 return mContext.getContentResolver().openFileDescriptor(mUri, "rw"); 184 } 185 186 /** 187 * Open the underlying file representing this media item. When a media 188 * item is successfully completed, you should 189 * {@link OutputStream#close()} and then {@link #publish()} it. 190 * 191 * @see #notifyProgress(int) 192 */ openOutputStream()193 public @NonNull OutputStream openOutputStream() throws FileNotFoundException { 194 return mContext.getContentResolver().openOutputStream(mUri); 195 } 196 197 /** 198 * When this media item is successfully completed, call this method to 199 * publish and make the final item visible to the user. 200 * 201 * @return the final {@code content://} Uri representing the newly 202 * published media. 203 */ publish()204 public @NonNull Uri publish() { 205 final ContentValues values = new ContentValues(); 206 values.put(MediaColumns.IS_PENDING, 0); 207 values.putNull(MediaColumns.DATE_EXPIRES); 208 mContext.getContentResolver().update(mUri, values, null, null); 209 return mUri; 210 } 211 212 /** 213 * When this media item has failed to be completed, call this method to 214 * destroy the pending item record and any data related to it. 215 */ abandon()216 public void abandon() { 217 mContext.getContentResolver().delete(mUri, null, null); 218 } 219 220 @Override close()221 public void close() { 222 // No resources to close, but at least we can inform people that no 223 // progress is being actively made. 224 } 225 } 226 } 227