Android系统目录预置media文件

刘高峯
2023-12-01

在处理Android平台的项目时,遇到客户提出的要求预置一个MP4类型的视频文件在系统目录。

经过参考一些文档,处理方案如下:

一、将媒体文件拷贝在out目录

方法类似预置第三方app

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) 
 
LOCAL_MODULE_TAGS := optional
LOCAL_POST_PROCESS_COMMAND := $(shell mkdir -p $(TARGET_OUT)/media/demo/)
LOCAL_POST_PROCESS_COMMAND := $(shell cp $(LOCAL_PATH)/demo.mp4 $(TARGET_OUT)/media/demo/)

需要拷贝的媒体文件为demo.mp4,预置在system/media/demo/

注意:此时媒体文件还未在系统存储的目录,还需要上层进行一次拷贝动作

二、第一次开机时将该文件拷贝进/storage/emulated/0/Movies

添加权限以及service的注册

--- a/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/AndroidManifest.xml
+++ b/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/AndroidManifest.xml
@@ -13,6 +13,7 @@
     <uses-permission android:name="android.permission.ACCESS_MTP" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+       <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />   
     <!-- M: Google protect using am.getRunningAppProcesse get other process info in diff uid,
     so we need add this permission to permit process.media, so that DrmHelper can use pid to
     query out process name. -->
@@ -82,6 +83,10 @@
                 <action android:name="mediatek.intent.action.OVERTIME_REMOVAL" />
             </intent-filter>
         </receiver>
+               
+               <service android:name="CopyFileService" android:exported="true">
+                       
+        </service>
 
         <service android:name="MediaScannerService" android:exported="true">
             <intent-filter>
--- a/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
+++ b/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
@@ -63,6 +63,18 @@ public class MediaScannerReceiver extends BroadcastReceiver {
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         Log.v(TAG, "onReceive action = " + action);
+               SharedPreferences sharedPreferences = context.getSharedPreferences("first_boot",Context.MODE_PRIVATE);
+               boolean first_boot= sharedPreferences.getBoolean("first_boot", true);//如果是第一次开机,则sharedPreferences 的值为空,赋值true
+               if (first_boot) {
+                       Log.v(TAG,"->CopyFileService");
+                       Intent activityIntent = new Intent();
+                       activityIntent.setClassName("com.android.providers.media", "com.android.providers.media.CopyFileService");
+                       context.startService(activityIntent);//启动拷贝文件的Services,由于文件比较大,onReceive方法里不能做耗时操作,可以用service解决
+               }
+               SharedPreferences.Editor editor1 = sharedPreferences.edit();
+               editor1.putBoolean("first_boot", false);//赋值false,表示下次开机不用再拷贝了
+               editor1.commit();
+                  
         if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
             Log.v(TAG,
             "onReceive BOOT_COMPLETED,begin to scan internal and external storage.");
(END)

只需要第一次开机进行拷贝就可以,防止后续重启每次都要进行重复操作。

CopyFileService.java

package com.android.providers.media;

import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class CopyFileService extends Service {

    private final static String TAG = "Monkey_CopyFileService";

    private static String PRELOAD_SRC = Environment.getRootDirectory()+"/media/demo";//*** 这个路径是/system/loadmedia
    private static String PRELOAD_DEST = "/storage/emulated/0/Movies";

    private CopyThread mCopyThread;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
		Log.d(TAG,"CopyFileService---------------");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG,"onStartCommand---------------");
        if (mCopyThread == null) {
            mCopyThread = new CopyThread();
            mCopyThread.start();
        }
        return Service.START_REDELIVER_INTENT;
    }


    public class CopyThread extends Thread {
        @Override
        public void run() {
            if (copyFolder(new File(PRELOAD_SRC), new File(PRELOAD_DEST))) {
                Log.e(TAG, "doPreloadMedia success !");
            } else {
                Log.e(TAG, "doPreloadMedia failed 。");
            }
			Log.e(TAG, "PRELOAD_SRC:"+PRELOAD_SRC);
			Log.e(TAG, "PRELOAD_DEST:"+PRELOAD_DEST);
            stopSelf();
        }
    }

    public boolean copyFolder(File srcFile, File destFile) {
        if (!srcFile.isDirectory()) {
            Log.i(TAG, "srcFile no isDirectory :"+srcFile.getName());
            return false;
        }
        if (!srcFile.canRead()) {
            Log.i(TAG, "no canRead :"+srcFile.getName());

        }
        if (!srcFile.canWrite()) {
            Log.i(TAG, "no canWrite :"+srcFile.getName());
        }

        if (!destFile.exists()) {
            boolean r = false;
            synchronized (this) {
                r = destFile.mkdirs();
            }
            Log.i(TAG, "destFile:exists " + r);
        }
        boolean result = true;
        File[] list = srcFile.listFiles();

        if (list == null) {
            Log.i(TAG, "copyFolder: list null =" + srcFile.getName());
            return false;
        }
        for (File f : list) {
			Log.i(TAG,"f.getName():"+f.getName());
            if (f.isDirectory()) {
                result &= copyFolder(f, new File(destFile, f.getName()));
            } else if(f.isFile()){
                result &= copyFile(f, new File(destFile, f.getName()));
            }
        }
		Log.i(TAG,"result:"+result);
        return result;
    }

    public boolean copyFile(File srcFile, File destFile) {
        boolean result = false;
        try {
            InputStream in = new FileInputStream(srcFile);
            try {
                result = copyToFile(in, destFile);
            } finally {
                in.close();
            }
        } catch (IOException e) {
            result = false;
        }
        return result;
    }

    /**
     * Copy data from a source stream to destFile.
     * Return true if succeed, return false if failed.
     */
    public boolean copyToFile(InputStream inputStream, File destFile) {
        try {
            if (destFile.exists()) {
                destFile.delete();
            }
            FileOutputStream out = new FileOutputStream(destFile);
            try {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            } finally {
                out.flush();
                try {
                    out.getFD().sync();
                } catch (IOException e) {
                }
                out.close();
            }
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}

PRELOAD_DEST 代表的是你要放置的目录这个可以通过adb进行获取。

PRELOAD_SRC 代表的是编译到system/media/demo/这个目录,位于out下。

 类似资料: