blob: a196c5a2333e58c74aa58f49d931364943a0770b [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.provider.cts.media;
import static android.provider.cts.media.MediaStoreTest.TAG;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Audio.Media;
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.MediaColumns;
import android.provider.cts.ProviderTestUtils;
import android.provider.cts.R;
import android.provider.cts.media.MediaStoreAudioTestHelper.Audio1;
import android.provider.cts.media.MediaStoreUtils.PendingParams;
import android.provider.cts.media.MediaStoreUtils.PendingSession;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import java.io.File;
import java.io.OutputStream;
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@RunWith(Parameterized.class)
public class MediaStore_Audio_MediaTest {
private Context mContext;
private ContentResolver mContentResolver;
private Uri mExternalAudio;
private Uri mExternalFiles;
@Parameter(0)
public String mVolumeName;
@Parameters
public static Iterable<? extends Object> data() {
return ProviderTestUtils.getSharedVolumeNames();
}
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mContentResolver = mContext.getContentResolver();
Log.d(TAG, "Using volume " + mVolumeName);
mExternalAudio = MediaStore.Audio.Media.getContentUri(mVolumeName);
mExternalFiles = MediaStore.Files.getContentUri(mVolumeName);
}
@Test
public void testGetContentUri() {
Cursor c = null;
assertNotNull(c = mContentResolver.query(
Media.getContentUri(mVolumeName), null, null,
null, null));
c.close();
assertEquals(ContentUris.withAppendedId(Media.getContentUri(mVolumeName), 42),
Media.getContentUri(mVolumeName, 42));
}
@Test
public void testGetContentUriForPath() {
Cursor c = null;
String externalPath = Environment.getExternalStorageDirectory().getPath();
assertNotNull(c = mContentResolver.query(Media.getContentUriForPath(externalPath), null, null,
null, null));
c.close();
String internalPath = mContext.getFilesDir().getAbsolutePath();
assertNotNull(c = mContentResolver.query(Media.getContentUriForPath(internalPath), null, null,
null, null));
c.close();
// Check other volume has correct uri
assertEquals(Media.getContentUri("0000-0000"),
Media.getContentUriForPath("/storage/0000-0000/foo.jpg"));
}
@Test
public void testStoreAudioMedia() {
Audio1 audio1 = Audio1.getInstance();
ContentValues values = audio1.getContentValues(mVolumeName);
//insert
Uri mediaUri = Media.getContentUri(mVolumeName);
Uri uri = mContentResolver.insert(mediaUri, values);
assertNotNull(uri);
try {
// query
// the following columns in the table are generated automatically when inserting:
// _ID, DATE_ADDED, ALBUM_ID, ALBUM_KEY, ARTIST_ID, ARTIST_KEY, TITLE_KEY
// the column DISPLAY_NAME will be ignored when inserting
Cursor c = mContentResolver.query(uri, null, null, null, null);
assertEquals(1, c.getCount());
c.moveToFirst();
long id = c.getLong(c.getColumnIndex(Media._ID));
assertTrue(id > 0);
String expected = audio1.getContentValues(mVolumeName).getAsString(Media.DATA);
assertEquals(expected, c.getString(c.getColumnIndex(Media.DATA)));
assertTrue(c.getLong(c.getColumnIndex(Media.DATE_ADDED)) > 0);
assertEquals(Audio1.DATE_MODIFIED, c.getLong(c.getColumnIndex(Media.DATE_MODIFIED)));
assertEquals(Audio1.DISPLAY_NAME, c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
assertEquals(Audio1.MIME_TYPE, c.getString(c.getColumnIndex(Media.MIME_TYPE)));
assertEquals(Audio1.SIZE, c.getInt(c.getColumnIndex(Media.SIZE)));
assertEquals(Audio1.TITLE, c.getString(c.getColumnIndex(Media.TITLE)));
assertEquals(Audio1.ALBUM, c.getString(c.getColumnIndex(Media.ALBUM)));
String albumKey = c.getString(c.getColumnIndex(Media.ALBUM_KEY));
assertNotNull(albumKey);
long albumId = c.getLong(c.getColumnIndex(Media.ALBUM_ID));
assertTrue(albumId > 0);
assertEquals(Audio1.ARTIST, c.getString(c.getColumnIndex(Media.ARTIST)));
String artistKey = c.getString(c.getColumnIndex(Media.ARTIST_KEY));
assertNotNull(artistKey);
long artistId = c.getLong(c.getColumnIndex(Media.ARTIST_ID));
assertTrue(artistId > 0);
assertEquals(Audio1.COMPOSER, c.getString(c.getColumnIndex(Media.COMPOSER)));
assertEquals(Audio1.DURATION, c.getLong(c.getColumnIndex(Media.DURATION)));
assertEquals(Audio1.IS_ALARM, c.getInt(c.getColumnIndex(Media.IS_ALARM)));
assertEquals(Audio1.IS_MUSIC, c.getInt(c.getColumnIndex(Media.IS_MUSIC)));
assertEquals(Audio1.IS_NOTIFICATION, c.getInt(c.getColumnIndex(Media.IS_NOTIFICATION)));
assertEquals(Audio1.IS_RINGTONE, c.getInt(c.getColumnIndex(Media.IS_RINGTONE)));
assertEquals(Audio1.IS_RECORDING, c.getInt(c.getColumnIndex(Media.IS_RECORDING)));
assertEquals(Audio1.TRACK, c.getInt(c.getColumnIndex(Media.TRACK)));
assertEquals(Audio1.YEAR, c.getInt(c.getColumnIndex(Media.YEAR)));
String titleKey = c.getString(c.getColumnIndex(Media.TITLE_KEY));
assertNotNull(titleKey);
c.close();
// test filtering
Uri baseUri = Media.getContentUri(mVolumeName);
Uri filterUri = baseUri.buildUpon()
.appendQueryParameter("filter", Audio1.ARTIST).build();
c = mContentResolver.query(filterUri, null, null, null, null);
assertEquals(1, c.getCount());
c.moveToFirst();
long fid = c.getLong(c.getColumnIndex(Media._ID));
assertTrue(id == fid);
c.close();
filterUri = baseUri.buildUpon().appendQueryParameter("filter", "xyzfoo").build();
c = mContentResolver.query(filterUri, null, null, null, null);
assertEquals(0, c.getCount());
c.close();
} finally {
// delete
int result = mContentResolver.delete(uri, null, null);
assertEquals(1, result);
}
}
@Test(timeout = 60000)
public void testCanonicalize() throws Exception {
// Remove all audio left over from other tests
ProviderTestUtils.executeShellCommand("content delete"
+ " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+ " --uri " + mExternalAudio,
InstrumentationRegistry.getInstrumentation().getUiAutomation());
// Publish some content
final File dir = ProviderTestUtils.stageDir(mVolumeName);
final Uri a = ProviderTestUtils.scanFileFromShell(
ProviderTestUtils.stageFile(R.raw.testmp3_2, new File(dir, "a.mp3")));
final Uri b = ProviderTestUtils.scanFileFromShell(
ProviderTestUtils.stageFile(R.raw.testmp3, new File(dir, "b.mp3")));
final Uri c = ProviderTestUtils.scanFileFromShell(
ProviderTestUtils.stageFile(R.raw.testmp3_2, new File(dir, "c.mp3")));
// Confirm we can canonicalize and recover it
final Uri canonicalized = mContentResolver.canonicalize(b);
assertNotNull(canonicalized);
assertEquals(b, mContentResolver.uncanonicalize(canonicalized));
// Delete all items above
mContentResolver.delete(a, null, null);
mContentResolver.delete(b, null, null);
mContentResolver.delete(c, null, null);
// Confirm canonical item isn't found
assertNull(mContentResolver.uncanonicalize(canonicalized));
// Publish data again and confirm we can recover it
final Uri d = ProviderTestUtils.scanFileFromShell(
ProviderTestUtils.stageFile(R.raw.testmp3, new File(dir, "d.mp3")));
assertEquals(d, mContentResolver.uncanonicalize(canonicalized));
}
@Test
public void testSortLocale() {
final Bundle queryArgs = new Bundle();
queryArgs.putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS,
new String[] { Audio.Media.TITLE });
for (String locale : new String[] {
"zh",
"zh@collation=pinyin",
"zh@collation=stroke",
"zh@collation=zhuyin",
}) {
queryArgs.putString(ContentResolver.QUERY_ARG_SORT_LOCALE, locale);
try (Cursor c = mContentResolver.query(mExternalAudio, null, queryArgs, null)) {
}
}
}
@Test
public void testTrack() throws Exception {
final Uri uri = ProviderTestUtils.stageMedia(R.raw.iso88591_11,
mExternalAudio, "audio/mpeg");
try (Cursor c = mContentResolver.query(uri, null, null, null)) {
assertTrue(c.moveToFirst());
// The media file is technically disc "1/2" and track "2/10", but we
// parse it into a funky format that has been around for years.
assertEquals(1002, c.getInt(c.getColumnIndex(MediaStore.Audio.Media.TRACK)));
}
}
/**
* Confirm that we can place both media and subtitles together in the same
* location on disk.
*/
@Test
public void testMediaWithSubtitles() throws Exception {
final String displayName = "cts" + System.nanoTime();
final String mediaDisplayName = displayName + ".mp3";
final String subDisplayName = displayName + ".lrc";
final PendingParams media = new PendingParams(
mExternalAudio, mediaDisplayName, "audio/mpeg");
final PendingParams sub = new PendingParams(
mExternalFiles, subDisplayName, "application/lrc");
media.setPath(Environment.DIRECTORY_MUSIC);
sub.setPath(Environment.DIRECTORY_MUSIC);
final Uri mediaUri = ContentUris.withAppendedId(mExternalFiles,
ContentUris.parseId(execPending(media)));
final Uri subUri = ContentUris.withAppendedId(mExternalFiles,
ContentUris.parseId(execPending(sub)));
final String[] projection = new String[] {
FileColumns.RELATIVE_PATH,
FileColumns.DISPLAY_NAME,
FileColumns.MEDIA_TYPE
};
// Confirm both files landed in same path
try (Cursor c = mContentResolver.query(mediaUri, projection, null, null)) {
assertTrue(c.moveToFirst());
assertEquals(Environment.DIRECTORY_MUSIC + '/', c.getString(0));
assertEquals(mediaDisplayName, c.getString(1));
assertEquals(FileColumns.MEDIA_TYPE_AUDIO, c.getInt(2));
}
try (Cursor c = mContentResolver.query(subUri, projection, null, null)) {
assertTrue(c.moveToFirst());
assertEquals(Environment.DIRECTORY_MUSIC + '/', c.getString(0));
assertEquals(subDisplayName, c.getString(1));
assertEquals(FileColumns.MEDIA_TYPE_SUBTITLE, c.getInt(2));
}
}
private Uri execPending(PendingParams params) throws Exception {
final Uri pendingUri = MediaStoreUtils.createPending(mContext, params);
try (PendingSession session = MediaStoreUtils.openPending(mContext, pendingUri)) {
try (OutputStream out = session.openOutputStream()) {
out.write((int) 42);
}
return session.publish();
}
}
}