This is through the system method to sd card and U disk plug monitoring and data acquisition, Android box end development, system permissions, of course, this is relatively simple, know the specific method, can be achieved through reflection.

First paste the effect picture:

Obtain the external storage device and monitor the plug – in status

Obtaining file contents

preface

During the boot process, the App uploads the specified configuration file through an external storage device (USB flash drive or SD card). At first, I didn’t plan to use the system method. I saw the library file Libaums on the Internet and tried to use it. But there seems to be no way to get the path, finally see the official also said NTFS format does not support, finally just use the system method, anyway have permission, really can do anything.

The body of the


You can see the system Settings inside, is able to listen to the NTFS format U disk (Evan_zch), and can obtain the files in the U disk, so easy to do, roll up the sleeves directly open dry.

1. Page positioning

To view the source code of a specific function, you can locate it through the interface, so that we can find the code we want faster. You can directly locate the package and class names of the current display interface by executing the following code.

linux:



adb shell dumpsys activity | grep "mFocusedActivity"



windows:



adb shell dumpsys activity | findstr "mFocusedActivity"

Copy the code

Execution Result:

At this time, you can locate the system Settings storage interface is StorageSettingsActivity. At this time, you can go to the Android OS website to search and view the corresponding source code.

Snipaste_2018-09-20_11-43-55.png

2. Source code analysis

Directly check the source code of the StorageSettings interface. It was relatively simple and generally easy to see because the project was tight and I didn’t study it carefully. I just posted some key codes to realize my needs.

private StorageManager mStorageManager;

/ / create StorageManager

mStorageManager = context.getSystemService(StorageManager.class);

// Register listener

mStorageManager.registerListener(mStorageListener);

Copy the code
// Listen for the callback

private final StorageEventListener mStorageListener = new StorageEventListener() {

        @Override

        public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {

            if (isInteresting(vol)) {

                refresh();

            }

        }



        @Override

        public void onDiskDestroyed(DiskInfo disk) {

            refresh();

        }

    };







private static boolean isInteresting(VolumeInfo vol) {

        switch(vol.getType()) {

            // Built-in storage device

            case VolumeInfo.TYPE_PRIVATE:

            External storage device

            case VolumeInfo.TYPE_PUBLIC:

                return true;

            default:

                return false;

        }

    }

Copy the code

In the source code, directly create StorageManager in the onCreate method and then registerListener to register the listening of the storage device, in the listening callback can directly judge the state of the storage device, Here are the oldState and newState parameters in the onVolumeStateChanged callback. By viewing the source code, you can find that the VolumeInfo class has set some basic storage device states.

    public static final int STATE_UNMOUNTED = 0;

    public static final int STATE_CHECKING = 1;

    public static final int STATE_MOUNTED = 2;

    public static final int STATE_MOUNTED_READ_ONLY = 3;

    public static final int STATE_FORMATTING = 4;

    public static final int STATE_EJECTING = 5;

    public static final int STATE_UNMOUNTABLE = 6;

    public static final int STATE_REMOVED = 7;

    public static final int STATE_BAD_REMOVAL = 8;

Copy the code

Add print log to callback:


Background logs show that the STATUS of the USB disk changes as follows:



STATE_UNMOUNTED— >
STATE_CHECKING— >
STATE_MOUNTED


Usb disk insert log


When the USB disk is removed, the state changes:



STATE_EJECTING— >
STATE_UNMOUNTED— >
STATE_BAD_REMOVAL


The listener callback is finally called
onDiskDestroyedMethods.


Usb disk unplugging logs

In order to avoid multiple callbacks to onVolumeStateChanged, I wrote isMounted, we can add isMounted to onVolumeStateChanged, The UI is updated only after an external storage device is mounted successfully.

 public boolean isMounted(VolumeInfo vol, int oldState, int newState) {

        return(isInteresting(vol) && oldState ! = newState && newState == VolumeInfo.STATE_MOUNTED);

    }





    private static boolean isInteresting(VolumeInfo vol) {

        switch (vol.getType()) {

            // We only care about external storage devices here, so we comment out TYPE_PRIVATE directly

            // case VolumeInfo.TYPE_PRIVATE:

            case VolumeInfo.TYPE_PUBLIC:

                return true;

            default:

                return false;

        }

    }

Copy the code

After listening for callbacks, you can use the getVolumes method of the StorageManager class to obtain all storage devices.

public List<VolumeInfo> getStorageDeviceList({

        if (mStorageManager == null) {

            throw new RuntimeException("StorageManagerUtils not init");

        }

        List<VolumeInfo> volumes = mStorageManager.getVolumes();

        List<VolumeInfo> publicVolumes = new ArrayList<>();

        publicVolumes.clear();

        for (VolumeInfo info : volumes) {

            int type = info.getType();

            // Obtain the path of the current storage device

            File path = volumeInfo.getPath();

            // Again, only care about external storage devices.

            if (info.getType() == VolumeInfo.TYPE_PUBLIC) {

                publicVolumes.add(info);

            }else if(info.getType() == VolumeInfo.TYPE_PRIVATE){

                // Obtain the built-in storage device

            }

        }

        return publicVolumes;

    }

Copy the code

After obtaining the usb flash drive, you can use the getPath method of the VolumeInfo class to obtain the specific path of the USB flash drive


After you can directly obtain the FILE U disk through this path, basically done, time is a little urgent, write a little rough, there is time to sort it out.


Finally, post the complete code for the utility class:

/ * *

 * @author Evan_zch

 * @date2018/9/17 nobleman

 * <p>

* Storage device management

* /


public class StorageManagerUtils {



    private static final String TAG = "StorageManagerUtils";

    private final StorageManager mStorageManager;

    private static long totalBytes = 0;

    private static long usedBytes = 0;



    private static final class StorageManagerHolder {

        private static final StorageManagerUtils INSTANCE = new StorageManagerUtils();

    }



    public static StorageManagerUtils getInstance(a) {

        return StorageManagerHolder.INSTANCE;

    }



    private StorageManagerUtils(a) {

        mStorageManager = DigiTvApplication.getAppContext().getSystemService(StorageManager.class);

    }



    public List<VolumeInfo> getStorageDeviceList(a) {

        if (mStorageManager == null) {

            throw new RuntimeException("StorageManagerUtils not init");

        }

        List<VolumeInfo> volumes = mStorageManager.getVolumes();

        List<VolumeInfo> publicVolumes = new ArrayList<>();

        publicVolumes.clear();

        for (VolumeInfo info : volumes) {

            int type = info.getType();

            if (info.getType() == VolumeInfo.TYPE_PUBLIC) {

                Logutils.d(TAG + "--refresh type is public");

                String bestVolumeDescription = mStorageManager.getBestVolumeDescription(info);

                File path = info.getPath();

                Logutils.d(TAG + "--refresh type=" + type + ",bestVolumeDescription=" + bestVolumeDescription + ",path=" + path);

                publicVolumes.add(info);

            }

        }

        return publicVolumes;

    }



    public boolean isMounted(VolumeInfo vol, int oldState, int newState) {

        return(isInteresting(vol) && oldState ! = newState && newState == VolumeInfo.STATE_MOUNTED);

    }



    private static boolean isInteresting(VolumeInfo vol) {

        switch (vol.getType()) {

            //case VolumeInfo.TYPE_PRIVATE:

            case VolumeInfo.TYPE_PUBLIC:

                return true;

            default:

                return false;

        }

    }



    public String getTotalSize(VolumeInfo vol) {

        if (vol.isMountedReadable()) {

            final File path = vol.getPath();

            if (totalBytes <= 0) {

                totalBytes = path.getTotalSpace();

            }

        }

        return Formatter.formatFileSize(DigiTvApplication.getAppContext(), totalBytes);

    }



    public String getUsedSize(VolumeInfo vol) {

        if (vol.isMountedReadable()) {

            final File path = vol.getPath();

            final long freeBytes = path.getFreeSpace();

            usedBytes = totalBytes - freeBytes;

        }

        return Formatter.formatFileSize(DigiTvApplication.getAppContext(), usedBytes);

    }

}

Copy the code