blob: 96bf2d5cd59bec91e1c988a8ae4cc2abc7f5b9d1 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.storage;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.util.Log;
import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
/**
* StorageManager is the interface to the systems storage service.
* Get an instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String)} with an argument
* of {@link android.content.Context#STORAGE_SERVICE}.
*/
public class StorageManager
{
private static final String TAG = "StorageManager";
/*
* Our internal MountService binder reference
*/
private IMountService mMountService;
/*
* The looper target for callbacks
*/
Looper mTgtLooper;
/*
* Target listener for binder callbacks
*/
private MountServiceBinderListener mBinderListener;
/*
* List of our listeners
*/
private ArrayList<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
private class MountServiceBinderListener extends IMountServiceListener.Stub {
public void onUsbMassStorageConnectionChanged(boolean available) {
final int size = mListeners.size();
for (int i = 0; i < size; i++) {
mListeners.get(i).sendShareAvailabilityChanged(available);
}
}
public void onStorageStateChanged(String path, String oldState, String newState) {
final int size = mListeners.size();
for (int i = 0; i < size; i++) {
mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
}
}
}
/**
* Private base class for messages sent between the callback thread
* and the target looper handler.
*/
private class StorageEvent {
public static final int EVENT_UMS_CONNECTION_CHANGED = 1;
public static final int EVENT_STORAGE_STATE_CHANGED = 2;
private Message mMessage;
public StorageEvent(int what) {
mMessage = Message.obtain();
mMessage.what = what;
mMessage.obj = this;
}
public Message getMessage() {
return mMessage;
}
}
/**
* Message sent on a USB mass storage connection change.
*/
private class UmsConnectionChangedStorageEvent extends StorageEvent {
public boolean available;
public UmsConnectionChangedStorageEvent(boolean a) {
super(EVENT_UMS_CONNECTION_CHANGED);
available = a;
}
}
/**
* Message sent on volume state change.
*/
private class StorageStateChangedStorageEvent extends StorageEvent {
public String path;
public String oldState;
public String newState;
public StorageStateChangedStorageEvent(String p, String oldS, String newS) {
super(EVENT_STORAGE_STATE_CHANGED);
path = p;
oldState = oldS;
newState = newS;
}
}
/**
* Private class containing sender and receiver code for StorageEvents.
*/
private class ListenerDelegate {
final StorageEventListener mStorageEventListener;
private final Handler mHandler;
ListenerDelegate(StorageEventListener listener) {
mStorageEventListener = listener;
mHandler = new Handler(mTgtLooper) {
@Override
public void handleMessage(Message msg) {
StorageEvent e = (StorageEvent) msg.obj;
if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) {
UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e;
mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
} else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) {
StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e;
mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState);
} else {
Log.e(TAG, "Unsupported event " + msg.what);
}
}
};
}
StorageEventListener getListener() {
return mStorageEventListener;
}
void sendShareAvailabilityChanged(boolean available) {
UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available);
mHandler.sendMessage(e.getMessage());
}
void sendStorageStateChanged(String path, String oldState, String newState) {
StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
mHandler.sendMessage(e.getMessage());
}
}
/**
* Constructs a StorageManager object through which an application can
* can communicate with the systems mount service.
*
* @param tgtLooper The {@android.os.Looper} which events will be received on.
*
* <p>Applications can get instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String)} with an argument
* of {@link android.content.Context#STORAGE_SERVICE}.
*
* @hide
*/
public StorageManager(Looper tgtLooper) throws RemoteException {
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
if (mMountService == null) {
Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
return;
}
mTgtLooper = tgtLooper;
mBinderListener = new MountServiceBinderListener();
mMountService.registerListener(mBinderListener);
}
/**
* Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
*
* @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
*
* @hide
*/
public void registerListener(StorageEventListener listener) {
if (listener == null) {
return;
}
synchronized (mListeners) {
mListeners.add(new ListenerDelegate(listener));
}
}
/**
* Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
*
* @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
*
* @hide
*/
public void unregisterListener(StorageEventListener listener) {
if (listener == null) {
return;
}
synchronized (mListeners) {
final int size = mListeners.size();
for (int i=0 ; i<size ; i++) {
ListenerDelegate l = mListeners.get(i);
if (l.getListener() == listener) {
mListeners.remove(i);
break;
}
}
}
}
/**
* Enables USB Mass Storage (UMS) on the device.
*
* @hide
*/
public void enableUsbMassStorage() {
try {
mMountService.setUsbMassStorageEnabled(true);
} catch (Exception ex) {
Log.e(TAG, "Failed to enable UMS", ex);
}
}
/**
* Disables USB Mass Storage (UMS) on the device.
*
* @hide
*/
public void disableUsbMassStorage() {
try {
mMountService.setUsbMassStorageEnabled(false);
} catch (Exception ex) {
Log.e(TAG, "Failed to disable UMS", ex);
}
}
/**
* Query if a USB Mass Storage (UMS) host is connected.
* @return true if UMS host is connected.
*
* @hide
*/
public boolean isUsbMassStorageConnected() {
try {
return mMountService.isUsbMassStorageConnected();
} catch (Exception ex) {
Log.e(TAG, "Failed to get UMS connection state", ex);
}
return false;
}
/**
* Query if a USB Mass Storage (UMS) is enabled on the device.
* @return true if UMS host is enabled.
*
* @hide
*/
public boolean isUsbMassStorageEnabled() {
try {
return mMountService.isUsbMassStorageEnabled();
} catch (RemoteException rex) {
Log.e(TAG, "Failed to get UMS enable state", rex);
}
return false;
}
/**
* Mount an OBB file.
*/
public boolean mountObb(String filename, String key) {
try {
return mMountService.mountObb(filename, key)
== StorageResultCode.OperationSucceeded;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
return false;
}
/**
* Mount an OBB file.
*/
public boolean unmountObb(String filename, boolean force) {
try {
return mMountService.unmountObb(filename, force)
== StorageResultCode.OperationSucceeded;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
return false;
}
public boolean isObbMounted(String filename) {
try {
return mMountService.isObbMounted(filename);
} catch (RemoteException e) {
Log.e(TAG, "Failed to check if OBB is mounted", e);
}
return false;
}
/**
* Check the mounted path of an OBB file.
*/
public String getMountedObbPath(String filename) {
try {
return mMountService.getMountedObbPath(filename);
} catch (RemoteException e) {
Log.e(TAG, "Failed to find mounted path for OBB", e);
}
return null;
}
}