IT_Programming/Android_Java

[ Android ] 디바이스 및 킷캣(Kitkat) 업데이트에 따른 갤러리 경로 호출 문제

JJun ™ 2015. 2. 25. 14:33



 출처: http://dark0946.tistory.com/archive/201407





이번에 대만 런칭 준비를 하며 디바이스 테스트를 해보던 중에 사진이 업로드 되지 않는 버그를 발견했다.

갤러리 호출 파트에서 디버깅을 해보니, Path 값이 들어오지 않아서 체크해보니 다음과 같이 나타남.



* 테스트 기종은 아래와 같으며, 두 디바이스 모두 Android Version - KitKat 으로 설치되어 있음.


*  HTC Zara :

content://com.android.providers.media.documents/document/image:1152


*  Samsung Galaxy S4 :

content://media/external/images/media/1152 


* Google Drive에서 사진 가져올 시 : 

content://com.google.android.apps.photos.content/3/https://lh5.googleusercontent.com/ABCD-EFGH=KJ flg=0x1


* 추가

겔럭시 시리즈에서 사진을 Picasa에 자동업로드 해주는 기능을 지원합니다.

해당 사진들을 읽어오면 Uri Path가 다음과 같은 형식으로 잡힙니다.

content://com.sec.android.gallery3d.provider ...........



킷캣으로 업데이트 되면서 외부저장소 호출이 가능한 함수가 새로 생겨났다.

( * 킷캣 업데이트 내용은 여기에서 확인할 수 있음 )


그러면서 호출 경로 부분에서도 약간의 변화가 생겼다. 기본적으로 사용하던 갤러리의 경로 ( content://media/external/images/media/ ) 가 좀 더 세분화되었다. 그 덕분에(?) uri에 셋팅된 경로가 바뀌면서 Segement 값을 잘못 읽어들이거나, 읽어들일수 없게 되어, 오류가 발생하게 된다.


경로를 받아와서 사진 데이터를 읽어들이는 방식에 대한 예외처리 작업이 조금 필요하다.

다음 코드는 Intent 를 받아와 getData를 통해 전달받은 Uri값으로 경로를 받아오는 부분이다.


// 선택한 이미지 경로 가져오기.  

public final String getPath(Uri uri) {  

      

    // TEST  

    // HTC:         content://com.android.providers.media.documents/document/image:.....  

    // GalaxyS4 :   content://media/external/images/media/....  

      

    // * 기존에 갤러리에서 호출했던 방식.  

    // Cursor c = mActivity.getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI,  

    //                                              null,  

    //                                              Images.Media._ID + "=?",  

    //                                              new String[] { uri.getLastPathSegment() } ,  

    //                                              null);  

    // @@@@@@  

    // content://com.android.providers.media.documents/document/image%....  

    // getAuthority = "com.android.providers.media.documents"  

    //  

    // content://media/external/images/media/....  

    // getAuthority = "media"  

    //   

      

    final boolean isAndroidVersionKitKat = Build.VERSION.SDK_INT >=  19; // ( == Build.VERSION_CODE.KITKAT )  

      

    // Check Google Drive.  

    if(isGooglePhotoUri(uri)) {  

        return uri.getLastPathSegment();  

    }  

      

    // 1. 안드로이드 버전 체크  

    // com.android.providers.media.documents/document/image :: uri로 전달 받는 경로가 킷캣으로 업데이트 되면서 변경 됨.  

    if(isAndroidVersionKitKat && DocumentManager.isDocumentID(uri)) {  

      

        //com.android.providers.media.documents/document/image:1234 ...  

        //  

        if(isMediaDocument(uri) && DocumentManager.isDocumentID(uri)) {  

            final String docId = DocumentManager.getDocumentId(uri);  

            final String[] split = docId.split(":");  

            final String type = split[0];  

  

            Uri contentUri = null;  

              

            if ("image".equals(type)) {  

                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;  

                  

            } else if ("video".equals(type)) {  

                return null; // 필자는 이미지만 처리할 예정이므로 비디오 및 오디오를 불러오는 부분은 작성하지 않음.  

                  

            } else if ("audio".equals(type)) {  

                return null;  

            }  

              

            final String selection = Images.Media._ID + "=?";  

            final String[] selectionArgs = new String[] {  

                    split[1]  

            };  

  

            return getDataColumn(mActivity.getApplicationContext(), contentUri, selection, selectionArgs);  

        }  

          

    }  

      

    // content://media/external/images/media/....  

    // 안드로이드 버전에 관계없이 경로가 com.android... 형식으로 집히지 않을 수 도 있음. [ 겔럭시S4 테스트 확인 ]  

    if(isPathSDCardType(uri)) {  

          

        final String selection = Images.Media._ID + "=?";  

           final String[] selectionArgs = new String[] {  

                   uri.getLastPathSegment()  

           };  

          

        return getDataColumn(mActivity.getApplicationContext(),  MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);  

    }  

      

    // File 접근일 경우  

    else if ("file".equalsIgnoreCase(uri.getScheme())) {  

        return uri.getPath();  

    }  

      

    return null;  

}  

  

  

  

// URI 를 받아서 Column 데이터 접근.  

public static String getDataColumn(Context context, Uri uri, String selection,  

        String[] selectionArgs) {  

  

    Cursor cursor = null;  

    final String column = "_data";  

    final String[] projection = {  

            column  

    };  

  

    try {  

          

        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs ,null);  

        if (cursor != null && cursor.moveToFirst()) {  

            final int column_index = cursor.getColumnIndexOrThrow(column);  

            return cursor.getString(column_index);  

        }  

          

    } finally {  

        if (cursor != null)  

            cursor.close();  

    }  

      

    return null;  

}  

  

// 킷캣에서 추가된  document식 Path  

public static boolean isMediaDocument(Uri uri) {  

      

    return "com.android.providers.media.documents".equals(uri.getAuthority());  

}  

  

// 기본 경로 ( 킷캣 이전버전 )  

public static boolean isPathSDCardType(Uri uri) {  

    // Path : external/images/media/ID(1234...)  

    return "external".equals(uri.getPathSegments().get(0));  

}  

  

// 구글 드라이브를 통한 업로드 여부 체크.  

public static boolean isGooglePhotoUri(Uri uri) {  

    return "com.google.android.apps.photos.content".equals(uri.getAuthority());  

}  

( * DocumentManager 는  API 19 SDK의 DocumentContract 와 동일합니다. 또는 여기 참고.)


* HTC Zara : 

content://com.android.providers.media.documents/document/image:1152


* Samsung Galaxy S4 :

content://media/external/images/media/1152 

From Google Drive : 

content://com.google.android.apps.photos.content/3/https://lh5.googleusercontent.com/ABCD-EFGH=KJ flg=0x1



결론은  uri.getAuthority() 와  uri.getLastPathSegement() 값을 분류해주는 작업만 잘 해주면 됨...

나머지 불러오는 방식은 일반 갤러리 호출 방식과 같음. 



:: 참고 사이트 ::

- 갤러리 또는 SD카드에서 이미지를 선택했을 때 절대경로 받아오는 방법

- URI로 실제 경로 받아오기

- 안드로이드 킷캣(Kitkat - API 19 ) 정보