StorageManager.java revision a45746efadd11bb7dfab026fb3c81a25fae74ca4
1b104340496e3a531e26c8f428c808eca0e039f50San Mehat/*
2b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Copyright (C) 2008 The Android Open Source Project
3b104340496e3a531e26c8f428c808eca0e039f50San Mehat *
4b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5b104340496e3a531e26c8f428c808eca0e039f50San Mehat * you may not use this file except in compliance with the License.
6b104340496e3a531e26c8f428c808eca0e039f50San Mehat * You may obtain a copy of the License at
7b104340496e3a531e26c8f428c808eca0e039f50San Mehat *
8b104340496e3a531e26c8f428c808eca0e039f50San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9b104340496e3a531e26c8f428c808eca0e039f50San Mehat *
10b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Unless required by applicable law or agreed to in writing, software
11b104340496e3a531e26c8f428c808eca0e039f50San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12b104340496e3a531e26c8f428c808eca0e039f50San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b104340496e3a531e26c8f428c808eca0e039f50San Mehat * See the License for the specific language governing permissions and
14b104340496e3a531e26c8f428c808eca0e039f50San Mehat * limitations under the License.
15b104340496e3a531e26c8f428c808eca0e039f50San Mehat */
16b104340496e3a531e26c8f428c808eca0e039f50San Mehat
17b104340496e3a531e26c8f428c808eca0e039f50San Mehatpackage android.os.storage;
18b104340496e3a531e26c8f428c808eca0e039f50San Mehat
19cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwoodimport android.os.Environment;
20b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.Handler;
21a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Looper;
22b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.Message;
232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable;
24a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.RemoteException;
25b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.ServiceManager;
26b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.util.Log;
27af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.util.SparseArray;
28b104340496e3a531e26c8f428c808eca0e039f50San Mehat
2905105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.lang.ref.WeakReference;
30b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport java.util.ArrayList;
3105105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.util.List;
32af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport java.util.concurrent.atomic.AtomicInteger;
33b104340496e3a531e26c8f428c808eca0e039f50San Mehat
34b104340496e3a531e26c8f428c808eca0e039f50San Mehat/**
3505105f7abe02b2dff91d6260b3628c8b97816babKenny Root * StorageManager is the interface to the systems storage service. The storage
3605105f7abe02b2dff91d6260b3628c8b97816babKenny Root * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
3705105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p>
3805105f7abe02b2dff91d6260b3628c8b97816babKenny Root * OBBs contain a filesystem that maybe be encrypted on disk and mounted
3905105f7abe02b2dff91d6260b3628c8b97816babKenny Root * on-demand from an application. OBBs are a good way of providing large amounts
4005105f7abe02b2dff91d6260b3628c8b97816babKenny Root * of binary assets without packaging them into APKs as they may be multiple
4105105f7abe02b2dff91d6260b3628c8b97816babKenny Root * gigabytes in size. However, due to their size, they're most likely stored in
4205105f7abe02b2dff91d6260b3628c8b97816babKenny Root * a shared storage pool accessible from all programs. The system does not
4305105f7abe02b2dff91d6260b3628c8b97816babKenny Root * guarantee the security of the OBB file itself: if any program modifies the
4405105f7abe02b2dff91d6260b3628c8b97816babKenny Root * OBB, there is no guarantee that a read from that OBB will produce the
4505105f7abe02b2dff91d6260b3628c8b97816babKenny Root * expected output.
4605105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p>
47b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Get an instance of this class by calling
4805105f7abe02b2dff91d6260b3628c8b97816babKenny Root * {@link android.content.Context#getSystemService(java.lang.String)} with an
4905105f7abe02b2dff91d6260b3628c8b97816babKenny Root * argument of {@link android.content.Context#STORAGE_SERVICE}.
50b104340496e3a531e26c8f428c808eca0e039f50San Mehat */
51b104340496e3a531e26c8f428c808eca0e039f50San Mehat
52b104340496e3a531e26c8f428c808eca0e039f50San Mehatpublic class StorageManager
53b104340496e3a531e26c8f428c808eca0e039f50San Mehat{
54b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private static final String TAG = "StorageManager";
55b104340496e3a531e26c8f428c808eca0e039f50San Mehat
56b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
57b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Our internal MountService binder reference
58b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
59b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private IMountService mMountService;
60b104340496e3a531e26c8f428c808eca0e039f50San Mehat
61b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
62b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * The looper target for callbacks
63b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
64b104340496e3a531e26c8f428c808eca0e039f50San Mehat    Looper mTgtLooper;
65b104340496e3a531e26c8f428c808eca0e039f50San Mehat
66b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
67b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Target listener for binder callbacks
68b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
69b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private MountServiceBinderListener mBinderListener;
70b104340496e3a531e26c8f428c808eca0e039f50San Mehat
71b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
72b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * List of our listeners
73b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
74af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private List<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
75af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
76af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    /*
77af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * Next available nonce
78af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     */
79af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    final private AtomicInteger mNextNonce = new AtomicInteger(0);
80b104340496e3a531e26c8f428c808eca0e039f50San Mehat
81b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private class MountServiceBinderListener extends IMountServiceListener.Stub {
82b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public void onUsbMassStorageConnectionChanged(boolean available) {
83b104340496e3a531e26c8f428c808eca0e039f50San Mehat            final int size = mListeners.size();
84b104340496e3a531e26c8f428c808eca0e039f50San Mehat            for (int i = 0; i < size; i++) {
85b104340496e3a531e26c8f428c808eca0e039f50San Mehat                mListeners.get(i).sendShareAvailabilityChanged(available);
86b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
87b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
88b104340496e3a531e26c8f428c808eca0e039f50San Mehat
89b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public void onStorageStateChanged(String path, String oldState, String newState) {
90b104340496e3a531e26c8f428c808eca0e039f50San Mehat            final int size = mListeners.size();
91b104340496e3a531e26c8f428c808eca0e039f50San Mehat            for (int i = 0; i < size; i++) {
92b104340496e3a531e26c8f428c808eca0e039f50San Mehat                mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
93b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
94b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
95b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
96b104340496e3a531e26c8f428c808eca0e039f50San Mehat
97b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
98a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Binder listener for OBB action results.
99a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
10005105f7abe02b2dff91d6260b3628c8b97816babKenny Root    private final ObbActionListener mObbActionListener = new ObbActionListener();
10105105f7abe02b2dff91d6260b3628c8b97816babKenny Root
10205105f7abe02b2dff91d6260b3628c8b97816babKenny Root    private class ObbActionListener extends IObbActionListener.Stub {
10337051cdd8624c4821bb68169be427061c48ad837Gilles Debunne        @SuppressWarnings("hiding")
104af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
10505105f7abe02b2dff91d6260b3628c8b97816babKenny Root
106a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
10737051cdd8624c4821bb68169be427061c48ad837Gilles Debunne        public void onObbResult(String filename, int nonce, int status) {
108af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbListenerDelegate delegate;
10905105f7abe02b2dff91d6260b3628c8b97816babKenny Root            synchronized (mListeners) {
110af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                delegate = mListeners.get(nonce);
111af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (delegate != null) {
112af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    mListeners.remove(nonce);
11305105f7abe02b2dff91d6260b3628c8b97816babKenny Root                }
11405105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
11505105f7abe02b2dff91d6260b3628c8b97816babKenny Root
116af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (delegate != null) {
117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                delegate.sendObbStateChanged(filename, status);
11805105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
12005105f7abe02b2dff91d6260b3628c8b97816babKenny Root
121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public int addListener(OnObbStateChangeListener listener) {
122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
12305105f7abe02b2dff91d6260b3628c8b97816babKenny Root
124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mListeners) {
125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mListeners.put(delegate.nonce, delegate);
12605105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            return delegate.nonce;
12905105f7abe02b2dff91d6260b3628c8b97816babKenny Root        }
13005105f7abe02b2dff91d6260b3628c8b97816babKenny Root    }
13105105f7abe02b2dff91d6260b3628c8b97816babKenny Root
132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private int getNextNonce() {
133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        return mNextNonce.getAndIncrement();
134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    }
135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
13605105f7abe02b2dff91d6260b3628c8b97816babKenny Root    /**
13705105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * Private class containing sender and receiver code for StorageEvents.
13805105f7abe02b2dff91d6260b3628c8b97816babKenny Root     */
13905105f7abe02b2dff91d6260b3628c8b97816babKenny Root    private class ObbListenerDelegate {
14005105f7abe02b2dff91d6260b3628c8b97816babKenny Root        private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
14105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        private final Handler mHandler;
14205105f7abe02b2dff91d6260b3628c8b97816babKenny Root
143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        private final int nonce;
144af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
14505105f7abe02b2dff91d6260b3628c8b97816babKenny Root        ObbListenerDelegate(OnObbStateChangeListener listener) {
146af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            nonce = getNextNonce();
14705105f7abe02b2dff91d6260b3628c8b97816babKenny Root            mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
14805105f7abe02b2dff91d6260b3628c8b97816babKenny Root            mHandler = new Handler(mTgtLooper) {
14905105f7abe02b2dff91d6260b3628c8b97816babKenny Root                @Override
15005105f7abe02b2dff91d6260b3628c8b97816babKenny Root                public void handleMessage(Message msg) {
15137051cdd8624c4821bb68169be427061c48ad837Gilles Debunne                    final OnObbStateChangeListener changeListener = getListener();
15237051cdd8624c4821bb68169be427061c48ad837Gilles Debunne                    if (changeListener == null) {
15305105f7abe02b2dff91d6260b3628c8b97816babKenny Root                        return;
15405105f7abe02b2dff91d6260b3628c8b97816babKenny Root                    }
15505105f7abe02b2dff91d6260b3628c8b97816babKenny Root
15605105f7abe02b2dff91d6260b3628c8b97816babKenny Root                    StorageEvent e = (StorageEvent) msg.obj;
15705105f7abe02b2dff91d6260b3628c8b97816babKenny Root
15805105f7abe02b2dff91d6260b3628c8b97816babKenny Root                    if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) {
15905105f7abe02b2dff91d6260b3628c8b97816babKenny Root                        ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e;
16037051cdd8624c4821bb68169be427061c48ad837Gilles Debunne                        changeListener.onObbStateChange(ev.path, ev.state);
16105105f7abe02b2dff91d6260b3628c8b97816babKenny Root                    } else {
16205105f7abe02b2dff91d6260b3628c8b97816babKenny Root                        Log.e(TAG, "Unsupported event " + msg.what);
16305105f7abe02b2dff91d6260b3628c8b97816babKenny Root                    }
16405105f7abe02b2dff91d6260b3628c8b97816babKenny Root                }
16505105f7abe02b2dff91d6260b3628c8b97816babKenny Root            };
16605105f7abe02b2dff91d6260b3628c8b97816babKenny Root        }
16705105f7abe02b2dff91d6260b3628c8b97816babKenny Root
16805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        OnObbStateChangeListener getListener() {
16905105f7abe02b2dff91d6260b3628c8b97816babKenny Root            if (mObbEventListenerRef == null) {
17005105f7abe02b2dff91d6260b3628c8b97816babKenny Root                return null;
17105105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
17205105f7abe02b2dff91d6260b3628c8b97816babKenny Root            return mObbEventListenerRef.get();
17305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        }
17405105f7abe02b2dff91d6260b3628c8b97816babKenny Root
175af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        void sendObbStateChanged(String path, int state) {
17605105f7abe02b2dff91d6260b3628c8b97816babKenny Root            ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state);
17705105f7abe02b2dff91d6260b3628c8b97816babKenny Root            mHandler.sendMessage(e.getMessage());
17805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        }
17905105f7abe02b2dff91d6260b3628c8b97816babKenny Root    }
18005105f7abe02b2dff91d6260b3628c8b97816babKenny Root
18105105f7abe02b2dff91d6260b3628c8b97816babKenny Root    /**
18205105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * Message sent during an OBB status change event.
18305105f7abe02b2dff91d6260b3628c8b97816babKenny Root     */
18405105f7abe02b2dff91d6260b3628c8b97816babKenny Root    private class ObbStateChangedStorageEvent extends StorageEvent {
18505105f7abe02b2dff91d6260b3628c8b97816babKenny Root        public final String path;
18605105f7abe02b2dff91d6260b3628c8b97816babKenny Root
187af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public final int state;
188af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
189af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public ObbStateChangedStorageEvent(String path, int state) {
19005105f7abe02b2dff91d6260b3628c8b97816babKenny Root            super(EVENT_OBB_STATE_CHANGED);
19105105f7abe02b2dff91d6260b3628c8b97816babKenny Root            this.path = path;
19205105f7abe02b2dff91d6260b3628c8b97816babKenny Root            this.state = state;
193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /**
197b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Private base class for messages sent between the callback thread
198b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * and the target looper handler.
199b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
200b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private class StorageEvent {
20105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        static final int EVENT_UMS_CONNECTION_CHANGED = 1;
20205105f7abe02b2dff91d6260b3628c8b97816babKenny Root        static final int EVENT_STORAGE_STATE_CHANGED = 2;
20305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        static final int EVENT_OBB_STATE_CHANGED = 3;
204b104340496e3a531e26c8f428c808eca0e039f50San Mehat
205b104340496e3a531e26c8f428c808eca0e039f50San Mehat        private Message mMessage;
206b104340496e3a531e26c8f428c808eca0e039f50San Mehat
207b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public StorageEvent(int what) {
208b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mMessage = Message.obtain();
209b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mMessage.what = what;
210b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mMessage.obj = this;
211b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
212b104340496e3a531e26c8f428c808eca0e039f50San Mehat
213b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public Message getMessage() {
214b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return mMessage;
215b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
216b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
217b104340496e3a531e26c8f428c808eca0e039f50San Mehat
218b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
219b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Message sent on a USB mass storage connection change.
220b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
221b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private class UmsConnectionChangedStorageEvent extends StorageEvent {
222b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public boolean available;
223b104340496e3a531e26c8f428c808eca0e039f50San Mehat
224b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public UmsConnectionChangedStorageEvent(boolean a) {
225b104340496e3a531e26c8f428c808eca0e039f50San Mehat            super(EVENT_UMS_CONNECTION_CHANGED);
226b104340496e3a531e26c8f428c808eca0e039f50San Mehat            available = a;
227b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
228b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
229b104340496e3a531e26c8f428c808eca0e039f50San Mehat
230b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
231b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Message sent on volume state change.
232b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
233b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private class StorageStateChangedStorageEvent extends StorageEvent {
234b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public String path;
235b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public String oldState;
236b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public String newState;
237b104340496e3a531e26c8f428c808eca0e039f50San Mehat
238b104340496e3a531e26c8f428c808eca0e039f50San Mehat        public StorageStateChangedStorageEvent(String p, String oldS, String newS) {
239b104340496e3a531e26c8f428c808eca0e039f50San Mehat            super(EVENT_STORAGE_STATE_CHANGED);
240b104340496e3a531e26c8f428c808eca0e039f50San Mehat            path = p;
241b104340496e3a531e26c8f428c808eca0e039f50San Mehat            oldState = oldS;
242b104340496e3a531e26c8f428c808eca0e039f50San Mehat            newState = newS;
243b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
244b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
245b104340496e3a531e26c8f428c808eca0e039f50San Mehat
246b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
247b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Private class containing sender and receiver code for StorageEvents.
248b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
249b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private class ListenerDelegate {
250b104340496e3a531e26c8f428c808eca0e039f50San Mehat        final StorageEventListener mStorageEventListener;
251b104340496e3a531e26c8f428c808eca0e039f50San Mehat        private final Handler mHandler;
252b104340496e3a531e26c8f428c808eca0e039f50San Mehat
253b104340496e3a531e26c8f428c808eca0e039f50San Mehat        ListenerDelegate(StorageEventListener listener) {
254b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mStorageEventListener = listener;
255b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mHandler = new Handler(mTgtLooper) {
256b104340496e3a531e26c8f428c808eca0e039f50San Mehat                @Override
257b104340496e3a531e26c8f428c808eca0e039f50San Mehat                public void handleMessage(Message msg) {
258b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    StorageEvent e = (StorageEvent) msg.obj;
259b104340496e3a531e26c8f428c808eca0e039f50San Mehat
260b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) {
261b104340496e3a531e26c8f428c808eca0e039f50San Mehat                        UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e;
262b104340496e3a531e26c8f428c808eca0e039f50San Mehat                        mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
263b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) {
264b104340496e3a531e26c8f428c808eca0e039f50San Mehat                        StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e;
265b104340496e3a531e26c8f428c808eca0e039f50San Mehat                        mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState);
266b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    } else {
267b104340496e3a531e26c8f428c808eca0e039f50San Mehat                        Log.e(TAG, "Unsupported event " + msg.what);
268b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    }
269b104340496e3a531e26c8f428c808eca0e039f50San Mehat                }
270b104340496e3a531e26c8f428c808eca0e039f50San Mehat            };
271b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
272b104340496e3a531e26c8f428c808eca0e039f50San Mehat
273b104340496e3a531e26c8f428c808eca0e039f50San Mehat        StorageEventListener getListener() {
274b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return mStorageEventListener;
275b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
276b104340496e3a531e26c8f428c808eca0e039f50San Mehat
277b104340496e3a531e26c8f428c808eca0e039f50San Mehat        void sendShareAvailabilityChanged(boolean available) {
278b104340496e3a531e26c8f428c808eca0e039f50San Mehat            UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available);
279b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mHandler.sendMessage(e.getMessage());
280b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
281b104340496e3a531e26c8f428c808eca0e039f50San Mehat
282b104340496e3a531e26c8f428c808eca0e039f50San Mehat        void sendStorageStateChanged(String path, String oldState, String newState) {
283b104340496e3a531e26c8f428c808eca0e039f50San Mehat            StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
284b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mHandler.sendMessage(e.getMessage());
285b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
286b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
287b104340496e3a531e26c8f428c808eca0e039f50San Mehat
288b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
289b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Constructs a StorageManager object through which an application can
290b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * can communicate with the systems mount service.
291b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
292a45746efadd11bb7dfab026fb3c81a25fae74ca4Jeff Smith     * @param tgtLooper The {@link android.os.Looper} which events will be received on.
293b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
294b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * <p>Applications can get instance of this class by calling
295b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
296b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * of {@link android.content.Context#STORAGE_SERVICE}.
297b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
298b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @hide
299b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
300b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public StorageManager(Looper tgtLooper) throws RemoteException {
301b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
302b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (mMountService == null) {
303b104340496e3a531e26c8f428c808eca0e039f50San Mehat            Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
304b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
305b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
306b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mTgtLooper = tgtLooper;
307b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mBinderListener = new MountServiceBinderListener();
308b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mMountService.registerListener(mBinderListener);
309b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
310b104340496e3a531e26c8f428c808eca0e039f50San Mehat
311b104340496e3a531e26c8f428c808eca0e039f50San Mehat
312b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
313b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
314b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
315b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
316b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
317ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
318b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
319b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public void registerListener(StorageEventListener listener) {
320b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (listener == null) {
321b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
322b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
323b104340496e3a531e26c8f428c808eca0e039f50San Mehat
324b104340496e3a531e26c8f428c808eca0e039f50San Mehat        synchronized (mListeners) {
325b104340496e3a531e26c8f428c808eca0e039f50San Mehat            mListeners.add(new ListenerDelegate(listener));
326b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
327b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
328b104340496e3a531e26c8f428c808eca0e039f50San Mehat
329b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
330b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
331b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
332b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
333b104340496e3a531e26c8f428c808eca0e039f50San Mehat     *
334ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
335b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
336b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public void unregisterListener(StorageEventListener listener) {
337b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (listener == null) {
338b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
339b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
340b104340496e3a531e26c8f428c808eca0e039f50San Mehat
341b104340496e3a531e26c8f428c808eca0e039f50San Mehat        synchronized (mListeners) {
342b104340496e3a531e26c8f428c808eca0e039f50San Mehat            final int size = mListeners.size();
343b104340496e3a531e26c8f428c808eca0e039f50San Mehat            for (int i=0 ; i<size ; i++) {
344b104340496e3a531e26c8f428c808eca0e039f50San Mehat                ListenerDelegate l = mListeners.get(i);
345b104340496e3a531e26c8f428c808eca0e039f50San Mehat                if (l.getListener() == listener) {
346b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    mListeners.remove(i);
347b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    break;
348b104340496e3a531e26c8f428c808eca0e039f50San Mehat                }
349b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
350b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
351b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
352b104340496e3a531e26c8f428c808eca0e039f50San Mehat
353b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
354b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Enables USB Mass Storage (UMS) on the device.
355ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     *
356ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
357b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
3580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void enableUsbMassStorage() {
359b104340496e3a531e26c8f428c808eca0e039f50San Mehat        try {
3600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mMountService.setUsbMassStorageEnabled(true);
361b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } catch (Exception ex) {
362b104340496e3a531e26c8f428c808eca0e039f50San Mehat            Log.e(TAG, "Failed to enable UMS", ex);
363b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
364b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
365b104340496e3a531e26c8f428c808eca0e039f50San Mehat
366b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
367b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Disables USB Mass Storage (UMS) on the device.
368ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     *
369ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
370b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
3710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void disableUsbMassStorage() {
372b104340496e3a531e26c8f428c808eca0e039f50San Mehat        try {
3730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mMountService.setUsbMassStorageEnabled(false);
374b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } catch (Exception ex) {
375b104340496e3a531e26c8f428c808eca0e039f50San Mehat            Log.e(TAG, "Failed to disable UMS", ex);
376b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
377b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
378b104340496e3a531e26c8f428c808eca0e039f50San Mehat
379b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
380b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Query if a USB Mass Storage (UMS) host is connected.
381b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @return true if UMS host is connected.
382ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     *
383ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
384b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
385b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
386b104340496e3a531e26c8f428c808eca0e039f50San Mehat        try {
387b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return mMountService.isUsbMassStorageConnected();
388b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } catch (Exception ex) {
389b104340496e3a531e26c8f428c808eca0e039f50San Mehat            Log.e(TAG, "Failed to get UMS connection state", ex);
390b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
391b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return false;
392b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
393b104340496e3a531e26c8f428c808eca0e039f50San Mehat
394b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /**
395b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * Query if a USB Mass Storage (UMS) is enabled on the device.
396b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @return true if UMS host is enabled.
397ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     *
398ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root     * @hide
399b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
400b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
401b104340496e3a531e26c8f428c808eca0e039f50San Mehat        try {
402b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return mMountService.isUsbMassStorageEnabled();
403b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } catch (RemoteException rex) {
404b104340496e3a531e26c8f428c808eca0e039f50San Mehat            Log.e(TAG, "Failed to get UMS enable state", rex);
405b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
406b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return false;
407b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
40802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
40902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
410a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
411a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * specified, it is supplied to the mounting process to be used in any
412a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * encryption used in the OBB.
413a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * <p>
41405105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * The OBB will remain mounted for as long as the StorageManager reference
41505105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * is held by the application. As soon as this reference is lost, the OBBs
416af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * in use will be unmounted. The {@link OnObbStateChangeListener} registered
417af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * with this call will receive the success or failure of this operation.
41805105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * <p>
419a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
420a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * file matches a package ID that is owned by the calling program's UID.
42105105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * That is, shared UID applications can attempt to mount any other
422a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * application's OBB that shares its UID.
423a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *
424a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @param filename the path to the OBB file
42505105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * @param key secret used to encrypt the OBB; may be <code>null</code> if no
42605105f7abe02b2dff91d6260b3628c8b97816babKenny Root     *            encryption was used on the OBB.
427af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * @param listener will receive the success or failure of the operation
428a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @return whether the mount call was successfully queued or not
42902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
43005105f7abe02b2dff91d6260b3628c8b97816babKenny Root    public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
431af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
432af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
433af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
434af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
435af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (listener == null) {
436af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("listener cannot be null");
437af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
438af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
43902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
440af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final int nonce = mObbActionListener.addListener(listener);
441af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mMountService.mountObb(filename, key, mObbActionListener, nonce);
442a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
44302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (RemoteException e) {
44402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Log.e(TAG, "Failed to mount OBB", e);
44502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
44602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
44702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return false;
44802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
44902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
45002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
45105105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
45205105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * <code>force</code> flag is true, it will kill any application needed to
45305105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * unmount the given OBB (even the calling application).
45405105f7abe02b2dff91d6260b3628c8b97816babKenny Root     * <p>
455af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * The {@link OnObbStateChangeListener} registered with this call will
456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * receive the success or failure of this operation.
457a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * <p>
458a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
459a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * file matches a package ID that is owned by the calling program's UID.
460a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * That is, shared UID applications can obtain access to any other
461a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * application's OBB that shares its UID.
46202ca31fbae9f35dd30f79de6927fae11b549391aKenny Root     * <p>
463a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *
464a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @param filename path to the OBB file
465a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @param force whether to kill any programs using this in order to unmount
466a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *            it
467af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root     * @param listener will receive the success or failure of the operation
468a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @return whether the unmount call was successfully queued or not
46902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
47038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener) {
471af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
472af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
473af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
474af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
475af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (listener == null) {
476af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("listener cannot be null");
477af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
478af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
47902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
480af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final int nonce = mObbActionListener.addListener(listener);
481af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mMountService.unmountObb(filename, force, mObbActionListener, nonce);
482a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
48302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (RemoteException e) {
48402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Log.e(TAG, "Failed to mount OBB", e);
48502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
48602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
48702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return false;
48802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
48902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /**
491a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Check whether an Opaque Binary Blob (OBB) is mounted or not.
492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *
493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @param filename path to OBB image
494a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @return true if OBB is mounted; false if not mounted or on error
495a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
496af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public boolean isObbMounted(String filename) {
497af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
498af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
499af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
500af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
50102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
50202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return mMountService.isObbMounted(filename);
50302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (RemoteException e) {
50402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Log.e(TAG, "Failed to check if OBB is mounted", e);
50502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
50602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
50702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return false;
50802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
50902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
51002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
511a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
512a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * give you the path to where you can obtain access to the internals of the
513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBB.
514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *
515a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @param filename path to OBB image
516a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * @return absolute path to mounted OBB image data or <code>null</code> if
517a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     *         not mounted or exception encountered trying to read status
51802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
51902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public String getMountedObbPath(String filename) {
520af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
521af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
522af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
52402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
52502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return mMountService.getMountedObbPath(filename);
52602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (RemoteException e) {
52702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Log.e(TAG, "Failed to find mounted path for OBB", e);
52802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
52902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
53002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return null;
53102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
532d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood
533d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    /**
534d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     * Gets the state of a volume via its mountpoint.
535d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     * @hide
536d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     */
537d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    public String getVolumeState(String mountPoint) {
538cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwood         if (mMountService == null) return Environment.MEDIA_REMOVED;
539d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        try {
540d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            return mMountService.getVolumeState(mountPoint);
541d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        } catch (RemoteException e) {
542d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            Log.e(TAG, "Failed to get volume state", e);
543d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            return null;
544d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        }
545d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    }
546d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood
547d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    /**
548d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     * Returns list of all mountable volumes.
549d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     * @hide
550d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood     */
5512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    public StorageVolume[] getVolumeList() {
552cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwood        if (mMountService == null) return new StorageVolume[0];
553d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        try {
5542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            Parcelable[] list = mMountService.getVolumeList();
5552f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            if (list == null) return new StorageVolume[0];
5562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            int length = list.length;
5572f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            StorageVolume[] result = new StorageVolume[length];
5582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            for (int i = 0; i < length; i++) {
5592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                result[i] = (StorageVolume)list[i];
5602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
5612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            return result;
562d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        } catch (RemoteException e) {
563d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            Log.e(TAG, "Failed to get volume list", e);
564d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            return null;
565d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        }
566d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    }
5672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
5682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    /**
5692f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood     * Returns list of paths for all mountable volumes.
5702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood     * @hide
5712f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood     */
5722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    public String[] getVolumePaths() {
5732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        StorageVolume[] volumes = getVolumeList();
5742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        if (volumes == null) return null;
5752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        int count = volumes.length;
5762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        String[] paths = new String[count];
5772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        for (int i = 0; i < count; i++) {
5782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            paths[i] = volumes[i].getPath();
5792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        }
5802f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        return paths;
5812f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    }
582b104340496e3a531e26c8f428c808eca0e039f50San Mehat}
583