Android 4.4文件管理器免ROOT破除外置SD卡限制

开源版本:
MediaStoreHack.java

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.util.Log;

import com.kk.kkfilemanager.R;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;

/**
 * Created by Luxuan on 2016/11/15.
 */

public class MediaStoreHackOnKitkat {

    private static final String ALBUM_ART_URI="content://media/external/audio/albumart";

    private static final String[] ALBUM_PROJECTION={
            BaseColumns._ID, MediaStore.Audio.AlbumColumns.ALBUM_ID,"media_type"
    };

    /**
     * Deletes the file. Returns true if the file has been successfully deleted or otherwise does
     * not exist. This operation is not recursive.
     */
    public static boolean delete(Context context, File file){
        String where=MediaStore.MediaColumns.DATA+"=?";
        String[] selectionArgs=new String[]{
                file.getAbsolutePath()
        };
        ContentResolver contentResolver=context.getContentResolver();
        // Delete the entry from the media database. This will actually delete media files.
        Uri fileUri=MediaStore.Files.getContentUri("external");
        // If the file is not a media file, create a new entry.
        contentResolver.delete(fileUri,where,selectionArgs);
        if(file.exists()){
            ContentValues values=new ContentValues();
            values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
            contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);
            contentResolver.delete(fileUri,where,selectionArgs);
        }
        return !file.exists();
    }

    private static File getExternalFilesDir(Context context){
        return context.getExternalFilesDir(null);
    }

    public static InputStream getInputStream(Context context, File file, long size) throws IOException{
        try{
            String where=MediaStore.MediaColumns.DATA+"=?";
            String[] selectionArgs=new String[]{
                    file.getAbsolutePath()
            };
            ContentResolver contentResolver=context.getContentResolver();
            Uri fileUri=MediaStore.Files.getContentUri("external");
            contentResolver.delete(fileUri,where,selectionArgs);
            ContentValues values=new ContentValues();
            values.put(MediaStore.MediaColumns.DATA,file.getAbsolutePath());
            values.put(MediaStore.MediaColumns.SIZE,size);
            Uri uri=contentResolver.insert(fileUri,values);
            if (uri == null) {
                // Should not occur.
                throw new IOException("Internal error.");
            }
            return contentResolver.openInputStream(uri);
        }catch(FileNotFoundException e){
            return null;
        }
    }

    public static OutputStream getOutputStream(String path, Context context) throws IOException{
        ContentResolver resolver=context.getContentResolver();
        File file=new File(path);
        if (file.exists() && file.isDirectory()) {
            throw new IOException("File exists and is a directory.");
        }

        // Delete any existing entry from the media database.
        // This may also delete the file (for media types), but that is irrelevant as it will be truncated momentarily in any case.
        String where = MediaStore.MediaColumns.DATA + "=?";
        String[] selectionArgs = new String[] { file.getAbsolutePath() };
        Uri filesUri = MediaStore.Files.getContentUri("external");
        resolver.delete(filesUri, where, selectionArgs);

        ContentValues values = new ContentValues();
        values.put(MediaStore.Files.FileColumns.DATA, file.getAbsolutePath());
        Uri uri = resolver.insert(filesUri, values);

        if (uri == null) {
            // Should not occur.
            throw new IOException("Internal error.");
        }
        return resolver.openOutputStream(uri);
    }

    /**
     * Returns an OutputStream to write to the file. The file will be truncated immediately.
     */

    private static int getTemporaryAlbumId(Context context){
        File temporaryTrack;
        try{
            temporaryTrack=installTemporaryTrack(context);
        }catch(IOException ex){
            return 0;
        }

        Uri fileUri=MediaStore.Files.getContentUri("external");
        String[] selectionArgs={
                temporaryTrack.getAbsolutePath()
        };
        ContentResolver contentResolver=context.getContentResolver();
        Cursor cursor=contentResolver.query(fileUri,ALBUM_PROJECTION,
                MediaStore.MediaColumns.DATA+" =?",selectionArgs,null);
        if(cursor==null||!cursor.moveToFirst()){
            if(cursor!=null){
                cursor.close();
            }
            ContentValues values=new ContentValues();
            values.put(MediaStore.MediaColumns.DATA,temporaryTrack.getAbsolutePath());
            values.put(MediaStore.MediaColumns.TITLE,"{MediaWrite Workaround}");
            values.put(MediaStore.MediaColumns.SIZE,temporaryTrack.length());
            values.put(MediaStore.MediaColumns.MIME_TYPE,"audio/mpeg");
            values.put(MediaStore.Audio.AudioColumns.IS_MUSIC,true);
            contentResolver.insert(fileUri,values);
        }
        cursor=contentResolver.query(fileUri,ALBUM_PROJECTION,MediaStore.MediaColumns.DATA+" =?",selectionArgs,null);
        if(cursor==null){
            return 0;
        }
        if(!cursor.moveToNext()){
            cursor.close();
            return 0;
        }
        int id=cursor.getInt(0);
        int albumId=cursor.getInt(1);
        int mediaType=cursor.getInt(2);
        cursor.close();
        ContentValues values=new ContentValues();
        boolean updateRequired=false;
        if(albumId==0){
            values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID,13371337);
            updateRequired=true;
        }
        if(mediaType!=2){
            values.put("media_type",2);
            updateRequired=true;
        }
        if(updateRequired){
            contentResolver.update(fileUri,values,BaseColumns._ID+"="+id,null);
        }
        cursor=contentResolver.query(fileUri,ALBUM_PROJECTION,MediaStore.MediaColumns.DATA+" =?",
                selectionArgs,null);
        if(cursor==null){
            return 0;
        }
        try{
            if(!cursor.moveToFirst()){
                return 0;
            }
            return cursor.getInt(1);
        }finally{
            cursor.close();
        }
    }

    private static File installTemporaryTrack(Context context) throws IOException{
        File externalFilesDir=getExternalFilesDir(context);
        if(externalFilesDir==null){
            return null;
        }

        File temporaryTrack=new File(externalFilesDir,"temptrack.mp3");
        if(!temporaryTrack.exists()){
            InputStream in=null;
            OutputStream out=null;
            try{
                in=context.getResources().openRawResource(R.raw.temptrack);
                out=new FileOutputStream(temporaryTrack);
                byte[] buffer=new byte[4096];
                int bytesRead;
                while((bytesRead=in.read(buffer))!=-1){
                    out.write(buffer,0,bytesRead);
                }
            }finally{
                out.close();
                in.close();
            }
        }
        return temporaryTrack;
    }

    public static boolean mkdir(Context context, File file) throws IOException {
        if (file.exists()) {
            return file.isDirectory();
        }
        File tmpFile = new File(file, ".MediaWriteTemp");
        int albumId = getTemporaryAlbumId(context);
        if (albumId == 0) {
            throw new IOException("Failed to create temporary album id.");
        }
        Uri albumUri = Uri.parse(String.format(Locale.US, ALBUM_ART_URI + "/%d", albumId));
        ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DATA, tmpFile.getAbsolutePath());
        ContentResolver contentResolver = context.getContentResolver();
        if (contentResolver.update(albumUri, values, null, null) == 0) {
            values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId);
            contentResolver.insert(Uri.parse(ALBUM_ART_URI), values);
        }
        try {
            ParcelFileDescriptor fd = contentResolver.openFileDescriptor(albumUri, "r");
            fd.close();
        }catch(Exception e){
            Log.d("Operation On Kitkat","Permission Denial.");
        }finally{
            delete(context,tmpFile);
        }
        return file.exists();
    }

}

复制功能:

public static String copyFile(Context context, String src, String dest){
    File file = new File(src);
    if (!file.exists() || file.isDirectory()) {
        Log.v(LOG_TAG, "copyFile: file not exist or is directory, " + src);
        return null;
    }
    InputStream input = null;
    OutputStream output = null;
    try {
        String destPath = Util.makePath(dest, file.getName());
        File destFile = new File(destPath);
        int i = 1;
        while (destFile.exists()) {
            String destName = Util.getNameFromFilename(file.getName()) + " " + i++ + "."
                    + Util.getExtFromFilename(file.getName());
            destPath = Util.makePath(dest, destName);
            destFile = new File(destPath);
        }

        input=MediaStoreHackOnKitkat.getInputStream(context,file,file.length());
        output = MediaStoreHackOnKitkat.getOutputStream(destPath, context);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = input.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
    }catch(IOException e){
        Log.e(LOG_TAG, "copyFile: " + e.toString());
    }finally{
        try {
            if (input != null)
                input.close();
            if (output != null)
                output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return null;
}

目前问题是:三星会有安全异常(Security Exception)。
三星和小米有Security Exception解决方法就是只能ROOT。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值