1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.xwalk.runtime.extension.api.device_capabilities;
7 import android.content.BroadcastReceiver;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.content.IntentFilter;
11 import android.os.Environment;
12 import android.os.StatFs;
13 import android.util.Log;
14 import android.util.SparseArray;
18 import org.json.JSONArray;
19 import org.json.JSONException;
20 import org.json.JSONObject;
21 import org.xwalk.runtime.extension.XWalkExtensionContext;
23 class DeviceCapabilitiesStorage {
24 private static final String TAG = "DeviceCapabilitiesStorage";
26 private DeviceCapabilities mDeviceCapabilities;
27 private XWalkExtensionContext mExtensionContext;
29 private static int mStorageCount = 0;
30 // Holds all available storages.
31 private final SparseArray<StorageUnit> mStorageList = new SparseArray<StorageUnit>();
33 private boolean mIsListening = false;
34 private IntentFilter mIntentFilter = new IntentFilter();
40 private long mCapacity;
41 private long mAvailCapacity;
44 public StorageUnit(int id, String name, String type) {
53 public int getId() { return mId; }
54 public String getName() { return mName; }
55 public String getType() { return mType; }
56 public String getPath() { return mPath; }
57 public long getCapacity() { return mCapacity; }
58 public long getAvailCapacity() { return mAvailCapacity; }
60 public void setType(String type) { mType = type;}
61 public void setPath(String path) {
66 public boolean isSame(StorageUnit unit) {
67 return mPath == unit.getPath();
70 public boolean isValid() {
71 if (mPath == null || mPath.isEmpty()) {
77 File file = new File(mPath);
78 return file.canRead();
81 public void updateCapacity() {
86 StatFs stat = new StatFs(mPath);
87 // FIXME(halton): After API level 18, use getTotalBytes() and
88 // getAvailableBytes() instead
89 long blockSize = stat.getBlockSize();
90 mCapacity = blockSize * stat.getBlockCount();
91 mAvailCapacity = blockSize * stat.getAvailableBlocks();
94 public JSONObject convertToJSON() {
95 JSONObject out = new JSONObject();
98 out.put("id", mId + 1); // Display from 1
99 out.put("name", mName);
100 out.put("type", mType);
101 out.put("capacity", mCapacity);
102 out.put("availCapacity", mAvailCapacity);
103 } catch (JSONException e) {
104 return mDeviceCapabilities.setErrorMessage(e.toString());
111 private final BroadcastReceiver mStorageListener = new BroadcastReceiver() {
113 public void onReceive(Context context, Intent intent) {
114 String action = intent.getAction();
115 if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
116 notifyAndSaveAttachedStorage();
119 if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)
120 || Intent.ACTION_MEDIA_REMOVED.equals(action)
121 || Intent.ACTION_MEDIA_BAD_REMOVAL.equals(action)) {
122 notifyAndRemoveDetachedStorage();
127 public DeviceCapabilitiesStorage(DeviceCapabilities instance,
128 XWalkExtensionContext context) {
129 mDeviceCapabilities = instance;
130 mExtensionContext = context;
132 registerIntentFilter();
134 // Fetch the original storage list
138 public JSONObject getInfo() {
139 JSONObject out = new JSONObject();
140 JSONArray arr = new JSONArray();
142 for(int i = 0; i < mStorageList.size(); i++) {
143 arr.put(mStorageList.valueAt(i).convertToJSON());
145 out.put("storages", arr);
146 } catch (JSONException e) {
147 return mDeviceCapabilities.setErrorMessage(e.toString());
153 private void initStorageList() {
154 mStorageList.clear();
157 StorageUnit unit = new StorageUnit(mStorageCount, "Internal", "fixed");
158 unit.setPath(Environment.getRootDirectory().getAbsolutePath());
159 mStorageList.put(mStorageCount, unit);
162 // Attempt to add emulated stroage first
163 int sdcardNum = mStorageCount - 1; // sdcard count from 0
164 unit = new StorageUnit(mStorageCount, new String("sdcard" + Integer.toString(sdcardNum)), "fixed");
165 if (Environment.isExternalStorageRemovable()) {
166 unit.setType("removable");
168 unit.setPath(Environment.getExternalStorageDirectory().getAbsolutePath());
170 if (unit.isValid()) {
171 mStorageList.put(mStorageCount, unit);
175 // Then attempt to add real removable storage
176 attemptAddExternalStorage();
179 private void registerIntentFilter() {
180 mIntentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
181 mIntentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
182 mIntentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);
183 mIntentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
184 mIntentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
185 mIntentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
186 mIntentFilter.addDataScheme("file");
189 private boolean attemptAddExternalStorage() {
190 int sdcardNum = mStorageCount - 1;
191 StorageUnit unit = new StorageUnit(mStorageCount, new String("sdcard" + Integer.toString(sdcardNum)), "removable");
192 unit.setPath("/storage/sdcard" + Integer.toString(sdcardNum));
194 if (!unit.isValid()) {
198 for(int i = 0; i < mStorageList.size(); i++) {
199 if (unit.isSame(mStorageList.valueAt(i))) {
204 mStorageList.put(mStorageCount, unit);
209 public void registerListener() {
215 mExtensionContext.getActivity().registerReceiver(mStorageListener, mIntentFilter);
218 public void unregisterListener() {
223 mIsListening = false;
224 mExtensionContext.getActivity().unregisterReceiver(mStorageListener);
227 private void notifyAndSaveAttachedStorage() {
228 if(!attemptAddExternalStorage()) {
232 StorageUnit unit = mStorageList.valueAt(mStorageList.size() - 1);
233 JSONObject out = new JSONObject();
235 out.put("reply", "attachStorage");
236 out.put("eventName", "storageattach");
237 out.put("data", unit.convertToJSON());
239 mDeviceCapabilities.broadcastMessage(out.toString());
240 } catch (JSONException e) {
241 mDeviceCapabilities.printErrorMessage(e);
246 private void notifyAndRemoveDetachedStorage() {
247 StorageUnit unit = mStorageList.valueAt(mStorageList.size() - 1);
249 if(unit.getType() != "removable") {
253 JSONObject out = new JSONObject();
255 out.put("reply", "detachStorage");
256 out.put("eventName", "storagedetach");
257 out.put("data", unit.convertToJSON());
259 mDeviceCapabilities.broadcastMessage(out.toString());
260 mStorageList.remove(unit.getId());
262 } catch (JSONException e) {
263 mDeviceCapabilities.printErrorMessage(e);
267 public void onResume() {
268 // Fistly, check the lasted external storage is valid.
269 // If not, remove it and send "ondetached" event.
270 StorageUnit lastUnit = mStorageList.valueAt(mStorageList.size() - 1);
271 if(!lastUnit.isValid()) {
272 notifyAndRemoveDetachedStorage();
275 // Secondly, attmpt to add a possible external storage and send "onattached" event.
276 notifyAndSaveAttachedStorage();
281 public void onPause() {
282 unregisterListener();
285 public void onDestroy() {