Как программно размонтировать USB DRIVE в Android 4.2
Я прочитал много сообщений на эту тему, но пока не нашел решения. В моем приложении мне нужно отключить USB DRIVE после копирования файлов с USB DRIVE на планшет, чтобы я мог безопасно удалить его, не используя меню "Настройки".
Прямо сейчас я использую этот метод:
Utility.copyDirectory(file,new File(_CURR_FOLDER));
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "umount" +
" " + SDPath + "\n" + "exit\n";
su.getOutputStream().write(cmd.getBytes());
Что я получаю в настройках хранения:
Общая площадь 0.0 Доступно 0.0
но SD все еще установлен.
Спасибо заранее за вашу помощь.
Первое редактирование:
Кто-то знает, как использовать IMountService? Я читал об этом, и, возможно, это правильный способ решить размонтирование USB DRIVE, но после добавления classes-full-debug.jar
мой проект больше не компилируется
3 ответа
Я использовал эти фрагменты кода в системном приложении, которое имеет право делать что угодно. Я не уверен, что это будет работать с обычными приложениями, даже если у него есть все права доступа к хранилищу.
Я знаю, что с опозданием на 7 лет, но, возможно, это поможет другим. Класс StorageManager имеет скрытую функцию, называемую unmount . Поскольку он не является общедоступным и блокирует поток вызывающего абонента, используйте отражение для доступа к нему и поместите его в AsyncTask:
public static void unmountStorage(Context context, String volId) {
new AsyncTask<Void, Void, Exception>() {
@Override
protected void onPostExecute(Exception e) {
if (e == null) {
Log.i("storageman", "unmounting " + volId + " success!");
}
else {
Log.e("storageman", "unmounting", e);
}
}
@Override
protected Exception doInBackground(Void... params) {
try {
StorageManager storageManager = context.getSystemService(StorageManager.class);
Method unmountMethod = StorageManager.class.getMethod("unmount", String.class);
unmountMethod.setAccessible(true);
unmountMethod.invoke(storageManager, volId);
return null;
}
catch (Exception ex) {
return ex;
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
The
volId
параметр немного сложно получить. Сначала перечислите доступные тома. StorageManager также имеет скрытый метод для этого, который называется getVolumes . Затем вы можете просмотреть их и получить их атрибуты, такие как идентификатор тома. Этот метод возвращает вам первое «внешнее» хранилище:
public static ExternalStorage getExternalStorage(Context context) {
try {
StorageManager storageManager = context.getSystemService(StorageManager.class);
Method getVolumes = StorageManager.class.getMethod("getVolumes");
getVolumes.setAccessible(true);
List<Object> volumes = (List<Object>) getVolumes.invoke(storageManager);
for (Object volume : volumes) {
Class<?> volumeInfoClass = Class.forName("android.os.storage.VolumeInfo");
Field idField = volumeInfoClass.getField("id");
idField.setAccessible(true);
String volumeId = (String) idField.get(volume);
Field nameField = volumeInfoClass.getField("fsLabel");
nameField.setAccessible(true);
String volumeName = (String) nameField.get(volume);
Field stateField = volumeInfoClass.getField("state");
stateField.setAccessible(true);
Integer volumeState = (Integer) stateField.get(volume);
Field pathField = volumeInfoClass.getField("path");
pathField.setAccessible(true);
String volumePath = (String) pathField.get(volume);
if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
return new ExternalStorage(volumeId, volumeName, new File(volumePath));
}
}
}
catch (Exception ex) {
Log.e("storagehelper", "getExternalStorage(Context context)", ex);
}
return null;
}
Я думаю, что эта строка требует дополнительного пояснения:
if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
Как я понял во время тестирования, идентификаторы томов внешних дисков начинаются с «общедоступных», поэтому я отфильтровал тома для него. Константы 2, 3 и 5 означают, что том смонтирован. Проверьте константы ЗДЕСЬ .
ExternalStorage — это простой класс данных, который я написал для хранения соответствующей информации.
Удачи!
Это не может быть сделано. Многие пользователи хранят весь свой контент, например, песни, видео, фотографии. это было хорошее решение по безопасности: не разрешать приложениям отключать SD-карту, а использовать их для хранения данных.
но вы можете отправить пользователя к настройке и пользователь сделает это, а не по коду
Intent i = new Intent(android.provider.Settings.ACTION_MEMORY_CARD_SETTINGS);
startActivity(i);
который поднимает этот экран...
я думаю это сработает
Это то, что я должен был сделать на Android 6.0.1, надеюсь, это будет то же самое для 4.2.
Мне пришлось добавить библиотеку SDK/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar в мое приложение после компиляции Android. (Я только что скачал версию леденца на палочке отсюда и, к счастью, она сработала и для зефира)
Студия Android будет жаловаться на ошибку нехватки памяти, это исправлено добавлением приведенного ниже кода в build.gradle внутри раздела android.
dexOptions {
javaMaxHeapSize "4g"
}
Вам также необходимо добавить поддержку мультидекса, добавив строки ниже в build.gradle внутри секции defaultConfig.
multiDexEnabled true
И добавление строки ниже в разделе зависимостей.
compile 'com.android.support:multidex:1.0.0'
И добавление строки ниже в разделе приложения внутри манифеста.
android:name="android.support.multidex.MultiDexApplication"
И ваш apk должен находиться в каталоге /system/priv-app и иметь разрешение ниже.
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
и тогда приведенный ниже код должен работать.
private void unmount() {
IMountService mountService = getMountService();
try {
if (mountService != null) {
mountService.unmountVolume("/mnt/media_rw/8842-89A4", true, false);
Log.e(TAG,"Unmounted");
} else {
Log.e(TAG, "Mount service is null, can't unmount");
}
} catch (RemoteException ex) {
// Not much can be done
}
}
private synchronized IMountService getMountService() {
if (mMountService == null) {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
mMountService = IMountService.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
}
return mMountService;
}