StorageManager.java revision 02c8730c1bf19daf48bec8c6995df676a00a73b1
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os.storage;
18
19import android.content.Context;
20import android.os.Binder;
21import android.os.Bundle;
22import android.os.Looper;
23import android.os.Parcelable;
24import android.os.ParcelFileDescriptor;
25import android.os.Process;
26import android.os.RemoteException;
27import android.os.Handler;
28import android.os.Message;
29import android.os.ServiceManager;
30import android.os.storage.IMountService;
31import android.os.storage.IMountServiceListener;
32import android.util.Log;
33import android.util.SparseArray;
34
35import java.io.FileDescriptor;
36import java.io.IOException;
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.HashMap;
40import java.util.List;
41
42/**
43 * StorageManager is the interface to the systems storage service.
44 * Get an instance of this class by calling
45 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
46 * of {@link android.content.Context#STORAGE_SERVICE}.
47 */
48
49public class StorageManager
50{
51    private static final String TAG = "StorageManager";
52
53    /*
54     * Our internal MountService binder reference
55     */
56    private IMountService mMountService;
57
58    /*
59     * The looper target for callbacks
60     */
61    Looper mTgtLooper;
62
63    /*
64     * Target listener for binder callbacks
65     */
66    private MountServiceBinderListener mBinderListener;
67
68    /*
69     * List of our listeners
70     */
71    private ArrayList<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
72
73    private class MountServiceBinderListener extends IMountServiceListener.Stub {
74        public void onUsbMassStorageConnectionChanged(boolean available) {
75            final int size = mListeners.size();
76            for (int i = 0; i < size; i++) {
77                mListeners.get(i).sendShareAvailabilityChanged(available);
78            }
79        }
80
81        public void onStorageStateChanged(String path, String oldState, String newState) {
82            final int size = mListeners.size();
83            for (int i = 0; i < size; i++) {
84                mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
85            }
86        }
87    }
88
89    /**
90     * Private base class for messages sent between the callback thread
91     * and the target looper handler.
92     */
93    private class StorageEvent {
94        public static final int EVENT_UMS_CONNECTION_CHANGED = 1;
95        public static final int EVENT_STORAGE_STATE_CHANGED   = 2;
96
97        private Message mMessage;
98
99        public StorageEvent(int what) {
100            mMessage = Message.obtain();
101            mMessage.what = what;
102            mMessage.obj = this;
103        }
104
105        public Message getMessage() {
106            return mMessage;
107        }
108    }
109
110    /**
111     * Message sent on a USB mass storage connection change.
112     */
113    private class UmsConnectionChangedStorageEvent extends StorageEvent {
114        public boolean available;
115
116        public UmsConnectionChangedStorageEvent(boolean a) {
117            super(EVENT_UMS_CONNECTION_CHANGED);
118            available = a;
119        }
120    }
121
122    /**
123     * Message sent on volume state change.
124     */
125    private class StorageStateChangedStorageEvent extends StorageEvent {
126        public String path;
127        public String oldState;
128        public String newState;
129
130        public StorageStateChangedStorageEvent(String p, String oldS, String newS) {
131            super(EVENT_STORAGE_STATE_CHANGED);
132            path = p;
133            oldState = oldS;
134            newState = newS;
135        }
136    }
137
138    /**
139     * Private class containing sender and receiver code for StorageEvents.
140     */
141    private class ListenerDelegate {
142        final StorageEventListener mStorageEventListener;
143        private final Handler mHandler;
144
145        ListenerDelegate(StorageEventListener listener) {
146            mStorageEventListener = listener;
147            mHandler = new Handler(mTgtLooper) {
148                @Override
149                public void handleMessage(Message msg) {
150                    StorageEvent e = (StorageEvent) msg.obj;
151
152                    if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) {
153                        UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e;
154                        mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
155                    } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) {
156                        StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e;
157                        mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState);
158                    } else {
159                        Log.e(TAG, "Unsupported event " + msg.what);
160                    }
161                }
162            };
163        }
164
165        StorageEventListener getListener() {
166            return mStorageEventListener;
167        }
168
169        void sendShareAvailabilityChanged(boolean available) {
170            UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available);
171            mHandler.sendMessage(e.getMessage());
172        }
173
174        void sendStorageStateChanged(String path, String oldState, String newState) {
175            StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
176            mHandler.sendMessage(e.getMessage());
177        }
178    }
179
180    /**
181     * Constructs a StorageManager object through which an application can
182     * can communicate with the systems mount service.
183     *
184     * @param tgtLooper The {@android.os.Looper} which events will be received on.
185     *
186     * <p>Applications can get instance of this class by calling
187     * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
188     * of {@link android.content.Context#STORAGE_SERVICE}.
189     *
190     * @hide
191     */
192    public StorageManager(Looper tgtLooper) throws RemoteException {
193        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
194        if (mMountService == null) {
195            Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
196            return;
197        }
198        mTgtLooper = tgtLooper;
199        mBinderListener = new MountServiceBinderListener();
200        mMountService.registerListener(mBinderListener);
201    }
202
203
204    /**
205     * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
206     *
207     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
208     *
209     * @hide
210     */
211    public void registerListener(StorageEventListener listener) {
212        if (listener == null) {
213            return;
214        }
215
216        synchronized (mListeners) {
217            mListeners.add(new ListenerDelegate(listener));
218        }
219    }
220
221    /**
222     * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
223     *
224     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
225     *
226     * @hide
227     */
228    public void unregisterListener(StorageEventListener listener) {
229        if (listener == null) {
230            return;
231        }
232
233        synchronized (mListeners) {
234            final int size = mListeners.size();
235            for (int i=0 ; i<size ; i++) {
236                ListenerDelegate l = mListeners.get(i);
237                if (l.getListener() == listener) {
238                    mListeners.remove(i);
239                    break;
240                }
241            }
242        }
243    }
244
245    /**
246     * Enables USB Mass Storage (UMS) on the device.
247     *
248     * @hide
249     */
250    public void enableUsbMassStorage() {
251        try {
252            mMountService.setUsbMassStorageEnabled(true);
253        } catch (Exception ex) {
254            Log.e(TAG, "Failed to enable UMS", ex);
255        }
256    }
257
258    /**
259     * Disables USB Mass Storage (UMS) on the device.
260     *
261     * @hide
262     */
263    public void disableUsbMassStorage() {
264        try {
265            mMountService.setUsbMassStorageEnabled(false);
266        } catch (Exception ex) {
267            Log.e(TAG, "Failed to disable UMS", ex);
268        }
269    }
270
271    /**
272     * Query if a USB Mass Storage (UMS) host is connected.
273     * @return true if UMS host is connected.
274     *
275     * @hide
276     */
277    public boolean isUsbMassStorageConnected() {
278        try {
279            return mMountService.isUsbMassStorageConnected();
280        } catch (Exception ex) {
281            Log.e(TAG, "Failed to get UMS connection state", ex);
282        }
283        return false;
284    }
285
286    /**
287     * Query if a USB Mass Storage (UMS) is enabled on the device.
288     * @return true if UMS host is enabled.
289     *
290     * @hide
291     */
292    public boolean isUsbMassStorageEnabled() {
293        try {
294            return mMountService.isUsbMassStorageEnabled();
295        } catch (RemoteException rex) {
296            Log.e(TAG, "Failed to get UMS enable state", rex);
297        }
298        return false;
299    }
300
301    /**
302     * Mount an OBB file.
303     */
304    public boolean mountObb(String filename, String key) {
305        try {
306            return mMountService.mountObb(filename, key)
307                    == StorageResultCode.OperationSucceeded;
308        } catch (RemoteException e) {
309            Log.e(TAG, "Failed to mount OBB", e);
310        }
311
312        return false;
313    }
314
315    /**
316     * Mount an OBB file.
317     */
318    public boolean unmountObb(String filename, boolean force) {
319        try {
320            return mMountService.unmountObb(filename, force)
321                    == StorageResultCode.OperationSucceeded;
322        } catch (RemoteException e) {
323            Log.e(TAG, "Failed to mount OBB", e);
324        }
325
326        return false;
327    }
328
329    public boolean isObbMounted(String filename) {
330        try {
331            return mMountService.isObbMounted(filename);
332        } catch (RemoteException e) {
333            Log.e(TAG, "Failed to check if OBB is mounted", e);
334        }
335
336        return false;
337    }
338
339    /**
340     * Check the mounted path of an OBB file.
341     */
342    public String getMountedObbPath(String filename) {
343        try {
344            return mMountService.getMountedObbPath(filename);
345        } catch (RemoteException e) {
346            Log.e(TAG, "Failed to find mounted path for OBB", e);
347        }
348
349        return null;
350    }
351}
352