android media scan (folder scan)

폴더를 생성하고 해당 폴더를 인식시키기 위해서는 scan을 해야한다.

Full Scan을 해도 되지만 이경우 Scan시 걸리는 시간이 오래걸린다.

그래서 Single Scan을 해보지만 단말에 따라 동작하지 않는것도 있다.

이럴때 ContentResolver 의 insert 를 이용하여 folder scan을 할 수도 있다.


<< Full Scan 방법 >>

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));


<< Single Scan 방법 : Not OK >>

      
	sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
	Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest")));    
	sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
		Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest/aaa")));    
	sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
		Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest/bbb")));
	Toast.makeText(MainActivity.this, "single scan: not ok ", Toast.LENGTH_SHORT).show();


<< ContentResolver 이용하는 방법 >>

      
	// getContentResolver().insert() 를 이용한 직접 폴더 정보 입력, only folder create scan
	
	final int DIR_FORMAT = 0x3001; // directory 
	Uri MediaUri = MediaStore.Files.getContentUri("external");
                
        ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest");
        values.put("format" , DIR_FORMAT);  //  
        values.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
        mContext.getContentResolver().insert(MediaUri, values);
                
        ContentValues values2 = new ContentValues();
        values2.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest/aaa");
        values2.put("format" , DIR_FORMAT);  //  
        values2.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
        mContext.getContentResolver().insert(MediaUri, values2);
                
        ContentValues values3 = new ContentValues();
        values3.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest/bbb");
        values3.put("format" , DIR_FORMAT);  //  
        values3.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
        mContext.getContentResolver().insert(MediaUri, values3);                
                
	Toast.makeText(MainActivity.this, "getContentResolver().insert() : ok ", Toast.LENGTH_SHORT).show();

<< 전체 소스 MainActivity.java >>

      
package com.example.foldertest;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	Context mContext;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext =  this;
        
        Button btn_create = (Button) findViewById(R.id.btn_create);
        Button btn_delete = (Button) findViewById(R.id.btn_delete);
        Button btn_scan =  (Button) findViewById(R.id.btn_scan);
        Button btn_single_scan =  (Button) findViewById(R.id.btn_single_scan);
        Button btn_resolver =  (Button) findViewById(R.id.btn_resolver);
        
        
        btn_create.setOnClickListener(new OnClickListener()
        {
			public void onClick(View v) {
				// 폴더 생성
		    	File path = new File("/sdcard/FolderTest");
			     if(! path.isDirectory()) {
			             path.mkdirs();
			      }

		    	File path2 = new File("/sdcard/FolderTest/aaa");
			     if(! path2.isDirectory()) {
			             path2.mkdirs();
			      }

		    	File path3 = new File("/sdcard/FolderTest/bbb");
			     if(! path3.isDirectory()) {
			             Boolean bResult = path3.mkdirs();
			             if(bResult){
			            	 Toast.makeText(MainActivity.this, "bbb folder create", Toast.LENGTH_SHORT).show();
			             }else{
			            	 Toast.makeText(MainActivity.this, "bbb folder create fail??????", Toast.LENGTH_SHORT).show();
			             }
			      }else{
			    	  Toast.makeText(MainActivity.this, "이미 bbb folder exist", Toast.LENGTH_SHORT).show();
			      }
				
			}
        });        
        
        btn_delete.setOnClickListener(new OnClickListener()
        {
			public void onClick(View v) {
				// 폴더 삭제
		    	File path2 = new File("/sdcard/FolderTest/aaa");
			     if(path2.isDirectory()) {
			             path2.delete();
			      }

		    	File path3 = new File("/sdcard/FolderTest/bbb");
			     if(path3.isDirectory()) {
			             path3.delete();
			      }

		    	File path = new File("/sdcard/FolderTest");
			     if(path.isDirectory()) {
			             Boolean bResult = path.delete();
			             if(bResult){
			            	 Toast.makeText(MainActivity.this, "schedle folder delete", Toast.LENGTH_SHORT).show();
			             }else{
			            	 Toast.makeText(MainActivity.this, "schedle folder delete fail ??????", Toast.LENGTH_SHORT).show();
			             }
			      }else{
			    	  Toast.makeText(MainActivity.this, "이미 schedle folder is not exist", Toast.LENGTH_SHORT).show();
			      }
			     
			     
			}
        });      
		     
        btn_scan.setOnClickListener(new OnClickListener()
        {
			public void onClick(View v) {
				// 미디어 스캔
				updateMediaScanMounted(mContext); 
			}
        });              
        
        btn_single_scan.setOnClickListener(new OnClickListener()
        {
			public void onClick(View v) {
				// 싱글 미디어 스캔, 폴더 스캔
	
	
				sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
						Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest")));    
				
//		        new Timer().schedule(new TimerTask() {
//		            @Override
//		            public void run() {
						sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
								Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest/aaa")));    
//		            }
//		        }, 1000);		// 1초후 실행          
//		        
				sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
						Uri.parse("file://"+ Environment.getExternalStorageDirectory() +"/FolderTest/bbb")));
				
				Toast.makeText(MainActivity.this, "single scan: not ok ", Toast.LENGTH_SHORT).show();

			}
        });             

        btn_resolver.setOnClickListener(new OnClickListener()
        {
			public void onClick(View v) {
				// getContentResolver().insert() 를 이용한 직접 폴더 정보 입력, only folder create scan
	
				final int DIR_FORMAT = 0x3001; // directory 
				Uri MediaUri = MediaStore.Files.getContentUri("external");
                
                ContentValues values = new ContentValues();
                values.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest");
                values.put("format" , DIR_FORMAT);  //  
                values.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                mContext.getContentResolver().insert(MediaUri, values);
//                mContext.getContentResolver().insert(MediaUri, values);  // 테스트용
//                mContext.getContentResolver().insert(MediaUri, values);  // 테스트용
                
                ContentValues values2 = new ContentValues();
                values2.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest/aaa");
                values2.put("format" , DIR_FORMAT);  //  
                values2.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                mContext.getContentResolver().insert(MediaUri, values2);
                
                ContentValues values3 = new ContentValues();
                values3.put(MediaStore.MediaColumns.DATA, Environment.getExternalStorageDirectory() +"/FolderTest/bbb");
                values3.put("format" , DIR_FORMAT);  //  
                values3.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                mContext.getContentResolver().insert(MediaUri, values3);                
                
				Toast.makeText(MainActivity.this, "getContentResolver().insert() : ok ", Toast.LENGTH_SHORT).show();

			}
        });       
 
        
    }
    
    public static void updateMediaScanMounted(Context context) {
    	context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
    }    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}
	


<< MediaScannerConnection 을 이용하여 Media scanning 하기 >>

출처: http://www.androidpub.com/android_dev_info/61238

안녕하세요. 앞의 글에서 MediaScanner 서비스를 실행하는 것이구요. 이글은 조금 더 복잡하지만 수동으로 Media Scanning을 하는 것입니다. http://developer.android.com/reference/android/media/MediaScannerConnection.html 위 링크에 설명이 있는데요. 생성자를 보면, MediaScannerConnection(Context context, MediaScannerConnection.MediaScannerConnectionClient client) Constructs a new MediaScannerConnection object. 이렇게 되어 있습니다. 생성자가 MediaScannerConnection.MediaScannerConnectionClient 를 필요로 하므로, 이것을 먼저 만들어 줍니다. private MediaScannerConnectionClient mScanClient = new MediaScannerConnectionClient(){ public void onMediaScannerConnected() { } public void onScanCompleted(String path, Uri uri) { } }; 이 클립스가 이렇게 코드를 생성해 줄텐데요. 위 두 함수를 채워 주면 됩니다. onMediaScannerConnected() 이 함수는 MediaScanner 서비스가 연결이 된 경우 호출이 되고, onScanCompleted() 이 함수는 스캔이 성공한 파일에 대한 정보를 전달해 줍니다. 우선 내용을 채우는 것은 아래 설명을 본 후에 채워 넣겠습니다. 이제 private MediaScannerConnection msc = new MediaScannerConnection(this, mScanClient); 이렇게 MediaScannerConnection 변수를 만들어 줍니다. MediaScannerConnection 의 함수들을 보면 아래와 같이 있습니다. Public Methods void connect() Initiates a connection to the media scanner service. void disconnect() Releases the connection to the media scanner service. synchronized boolean isConnected() Returns whether we are connected to the media scanner service void onServiceConnected(ComponentName className, IBinder service) Part of the ServiceConnection interface. void onServiceDisconnected(ComponentName className) Part of the ServiceConnection interface. void scanFile(String path, String mimeType) Requests the media scanner to scan a file. 버튼이나 어느곳이나 Media Scan을 시작하고 싶은 곳에서 msc.connect(); 을 호출합니다. 그럼, MediaScanner 서비스와 연결이 되면, MediaScannerConnectionClient 의 onMediaScannerConnected() 가 호출이 된답니다. 그러므로, 실제 scanFile을 할 수 있는 곳이 onMediaScannerConnected() 함수 안 이랍니다. 그리고, scanFile의 설명을 보면, 'a file' 이라고 명시하고 있습니다. scanFile의 path 값에는 /sdcard/* 이런 값은 들어가지 않는답니다. 넣어도 되지만 스캐닝이 안되지요. 이말은 스캐닝할 파일들을 알아서 찾아서 정확한 파일명으로 넣어주어야 된다는 것입니다. 이제 onMediaScannerConnected() 함수를 채워 보겠습니다. private MediaScannerConnectionClient mScanClient = new MediaScannerConnectionClient(){ public void onMediaScannerConnected() { Log.i(TAG, "onMediaScannerConnected"); File file = Environment.getExternalStorageDirectory(); // 외장 디렉토리 가져옴 File[] fileNames = file.listFiles(new FilenameFilter(){ // 특정 확장자만 가진 파일들을 필터링함 public boolean accept(File dir, String name){ return name.endsWith(".mp4") || name.endsWith(".avi") || name.endsWith(".wmv") ; } }); if (fileNames != null) { for (int i = 0; i < fileNames.length ; i++) // 파일 갯수 만큼 scanFile을 호출함 { msc.scanFile(fileNames[i].getAbsolutePath(), null); } } } public void onScanCompleted(String path, Uri uri) { Log.i(TAG, "onScanCompleted(" + path + ", " + uri.toString() + ")"); // 스캐닝한 정보를 출력해봄 } };

<< MediaScannerConnection 을 이용하여 Media scanning 하기 구현 테스트 >>

일단 임의의 파일 1개를 스캔하도록 테스트해보았다. 잘된다.

	// MediaScan
	MediaScanFile.getInstance(mContext, mCapturePhotoPath);

       // MediaScanFile.java
/**
 * 
 * 임의의 파일을 미디어 스캔하기
 * 
*/ public class MediaScanFile extends MediaScannerConnection { private static final String TAG = MediaScanFile.class.getSimpleName(); private static MediaScanFile mSingleton = null; private static String mPath = null; public static MediaScanFile getInstance(Context context, String path){ if(mSingleton == null){ mPath = path; mSingleton = new MediaScanFile(context, mScanClient); mSingleton.connect(); } return mSingleton; } private MediaScanFile(Context context, MediaScannerConnectionClient client) { super(context, client); // TODO Auto-generated constructor stub } private static MediaScannerConnectionClient mScanClient = new MediaScannerConnectionClient() { @Override public void onScanCompleted(String path, Uri uri) { Log.i(TAG, "onScanCompleted:"+path+", "+uri.toString()); mSingleton.disconnect(); mSingleton = null; } @Override public void onMediaScannerConnected() { mSingleton.scanFile(mPath, null); } }; }


<< MediaScanning 중인지 확인하기 >>

이미 미디어스캐닝 중일때 또 미디어 스캐닝을 요청하면 적절하지 않다.

그래서 풀 미디어 스캔을 할때는 이미 미디어 스캐닝중인지 확인이 필요하다.

출처: http://sudarnimalan.blogspot.kr/2012/05/android-how-to-check-if-media-scanner.html

[ 첫번째 방법]

     
public class MediaScannerBroadcastReceiver extends BroadcastReceiver {
	public static boolean mMedaiScanning = false;
        @Override
	public void onReceive(Context context, Intent intent) {
		if(intent.getAction().equals(Intent.ACTION_MEDIA_SCANNER_STARTED)){
			mMedaiScanning = true;
		}
		if(intent.getAction().equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)){
			mMedaiScanning = false;
		}
	}
}


//And register this in manifest file:


     < intent-filter>

           < action android:name="android.intent.action.MEDIA_SCANNER_FINISHED" >  < /action>
          < action android:name="android.intent.action.MEDIA_SCANNER_STARTED" >  < /action>
           < data android:scheme="file" >  < /data>
      < /intent-filter>



//Then in cases we we wanted to check the condition we sued as following:
if( MediaScannerBroadcastReceiver.mMedaiScanning){
     .....
}


[두번째 방법]


     
private boolean isMediaScannerRunning() {
	Cursor query = getContentResolver().query(MediaStore.getMediaScannerUri(),
                                                   new String[]{MediaStore.MEDIA_SCANNER_VOLUME}, null, null, null);
        if(query!=null){
        	if(query.moveToFirst()){
        		int columnIndex = query.getColumnIndex(MediaStore.MEDIA_SCANNER_VOLUME);
        		String volumeName = query.getString(columnIndex);
        		if(volumeName!=null){
        			return true;
        		}
        	}
        	query.close();
        }
        return false;
}


+ Recent posts