안녕하세요. 

우선  아래 링크의 글을 먼저 보실 것을 권합니다.
http://www.androidpub.com/48937

안드로이드는  SDK의 문서만으로  도저히  이해하기 힘든 것이  너무 많은 듯합니다.

다행히  소스가 공개되어 있어서  framework 쪽 소스까지 뒤져 보면서  동작을 확인해야,
SDK를 이용해서 프로그램을 짤 때  도움이 될듯 하네요.


이 글을  쓰게 된 이유는 

----------  이 궁금증에서 시작을 하였습니다. ----------------
Intent에서  Uri를 사용하여 새로운 activity 띄울 때가 좀 아리송하네요. 

     Uri uri = Uri.parse("content://media/internal/images/media");
     Intent intent = new Intent(Intent.ACTION_VIEW, uri);
     startActivity(intent);


위와 같이  코딩하고 실행하면,  

Gallery의  두번째 화면 ( 폴더들어가서 폴더 내용 보여주는 것 같은 화면) 이  뜹니다.
------------------------------------------------------------

보통 안드로이드 책이나  강좌에서는  Intent를 띄울 때  명시적으로  콤포넌트 이름을 정하던  class 를 사용하던지 해서  호출하는 것은  많이 나옵니다.


그런데,  위 궁금증처럼   URI 를 사용한 경우는  도대체 어느 쪽으로 가는지 알 수가 없더군요.
동작을 하는데 말이죠.



content://media/internal/images/media


우선 이 URI를 분석해 봅니다.

http://developer.android.com/reference/android/content/Intent.html

위 링크의 글을 보면  "Intent Resolution"에는   명시적인것과  암묵적인 것이 있는데,
암묵적인 것에 해당 한다는 이야기가 있구요.

http://developer.android.com/guide/topics/providers/content-providers.html

컨텐츠 프로바이더 설명 링크에 가보면,

Content URI Summary

Here is a recap of the important parts of a content URI:

Elements of a content URI

  1. Standard prefix indicating that the data is controlled by a content provider. It's never modified.
  2. The authority part of the URI; it identifies the content provider. For third-party applications, this should be a fully-qualified class name (reduced to lowercase) to ensure uniqueness. The authority is declared in the <provider> element's authorities attribute:

    <provider name=".TransportationProvider"

    authorities="com.example.transportationprovider"

    . . . >
  3. The path that the content provider uses to determine what kind of data is being requested. This can be zero or more segments long. If the content provider exposes only one type of data (only trains, for example), it can be absent. If the provider exposes several types, including subtypes, it can be several segments long — for example, "land/bus", "land/train", "sea/ship", and "sea/submarine" to give four possibilities.

  4. The ID of the specific record being requested, if any. This is the _ID value of the requested record. If the request is not limited to a single record, this segment and the trailing slash are omitted:

    content://com.example.transportationprovider/trains



이런 설명이 나오는 데요.   

위 설명대로면 


content://media/internal/images/media


여기서  authority 값으로   Provider 를 구분하는 값이라고 합니다.


그래서  안드로이드 OS 소스에서  찾아 보았더니

OS소스/packages/providers/MediaProvider

에서  관련 부분을 찾았답니다.


위 폴더의  AndroidManifest.xml 파일을 보면,


<application android:process="android.process.media"
                 android:label="@string/app_label">
        <provider android:name="MediaProvider"
            android:authorities="media"
                android:multiprocess="false" />


이렇게 되어 있습니다.

즉,   content://media/ 는   MediaProvider 프로젝트의  MediaProvider.java 가 담당하는 것이더군요.




다음으로  
content://media/internal/images/media

internal 부분을   MediaProvider.java  찾아보면,



                            String volume = srcuri.toString().substring(16, 24); // extract internal/external
                            Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId);
                            getContext().getContentResolver().notifyChange(uri, null);


이런  코드가 나옵니다.

internal부분은    volume 값으로    단말기의  내부인지 외부인지를  구분하는 용도더군요.


            DatabaseHelper db;
            if (INTERNAL_VOLUME.equals(volume)) {
                db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true);
            } else if (EXTERNAL_VOLUME.equals(volume)) {
                String path = Environment.getExternalStorageDirectory().getPath();
                int volumeID = FileUtils.getFatVolumeId(path);
                if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID);

                // generate database name based on volume ID
                String dbName = "external-" + Integer.toHexString(volumeID) + ".db";
                db = new DatabaseHelper(getContext(), dbName, false);
            } else {
                throw new IllegalArgumentException("There is no volume named " + volume);
            }

internal 인 경우,   "internal.db" 파일을  열고,

external 인경우,    external-volumeID.db  파일을  열더군요.

db 파일들은

# pwd
pwd
/data/data/com.android.providers.media/databases
# ls
ls
external-12e23719.db
external-a0e3d1c.db
internal.db
#
위와 같이 들어 있더군요.




다음으로  
content://media/internal/images/media

녹색 부분도   소스에 보면  무슨 의미인지 알수 있는 소스가 있는데요.


static
    {
        URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA);
        URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID);
        URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS);
        URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID);

        URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA);
        URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID);
        URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES);
        URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID);
        URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS);
        URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID);
        URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES);
                                         ... 중략.....


이런식으로  URI의  뒷부분을  비교하여  실제로  어느 테이블에 데이터를 가져올지를 구분하더군요.


switch (table) {
            case IMAGES_MEDIA:
                qb.setTables("images");
                if (uri.getQueryParameter("distinct") != null)
                    qb.setDistinct(true);
                break;



이렇게   실제로는   images  테이블을  가져 오고 있습니다.




수고하세요 ^^