resolved conflicts for merge of fc4a3d37 to master

Change-Id: I40f603ba9330c3e882f4d58398095f4094725b21
This commit is contained in:
Mike Lockwood
2011-05-16 15:49:53 -04:00
9 changed files with 385 additions and 42 deletions

View File

@@ -18,6 +18,7 @@ package android.os;
import android.content.res.Resources;
import android.os.storage.IMountService;
import android.os.storage.StorageVolume;
import android.util.Log;
import java.io.File;
@@ -35,7 +36,25 @@ public class Environment {
private static final Object mLock = new Object();
private volatile static Boolean mIsExternalStorageEmulated = null;
private volatile static StorageVolume mPrimaryVolume = null;
private static StorageVolume getPrimaryVolume() {
if (mPrimaryVolume == null) {
synchronized (mLock) {
if (mPrimaryVolume == null) {
try {
IMountService mountService = IMountService.Stub.asInterface(ServiceManager
.getService("mount"));
Parcelable[] volumes = mountService.getVolumeList();
mPrimaryVolume = (StorageVolume)volumes[0];
} catch (Exception e) {
Log.e(TAG, "couldn't talk to MountService", e);
}
}
}
}
return mPrimaryVolume;
}
/**
* Gets the Android root directory.
@@ -416,9 +435,8 @@ public class Environment {
* <p>See {@link #getExternalStorageDirectory()} for more information.
*/
public static boolean isExternalStorageRemovable() {
if (isExternalStorageEmulated()) return false;
return Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_externalStorageRemovable);
StorageVolume volume = getPrimaryVolume();
return (volume != null && volume.isRemovable());
}
/**
@@ -435,23 +453,8 @@ public class Environment {
* android.content.ComponentName, boolean)} for additional details.
*/
public static boolean isExternalStorageEmulated() {
if (mIsExternalStorageEmulated == null) {
synchronized (mLock) {
if (mIsExternalStorageEmulated == null) {
boolean externalStorageEmulated;
try {
IMountService mountService = IMountService.Stub.asInterface(ServiceManager
.getService("mount"));
externalStorageEmulated = mountService.isExternalStorageEmulated();
mIsExternalStorageEmulated = Boolean.valueOf(externalStorageEmulated);
} catch (Exception e) {
Log.e(TAG, "couldn't talk to MountService", e);
return false;
}
}
}
}
return mIsExternalStorageEmulated;
StorageVolume volume = getPrimaryVolume();
return (volume != null && volume.isEmulated());
}
static File getDirectory(String variableName, String defaultPath) {

View File

@@ -20,7 +20,9 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.storage.StorageVolume;
/**
* WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -638,15 +640,15 @@ public interface IMountService extends IInterface {
return _result;
}
public String[] getVolumeList() throws RemoteException {
public Parcelable[] getVolumeList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
String[] _result;
Parcelable[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
_reply.readException();
_result = _reply.readStringArray();
_result = _reply.readParcelableArray(StorageVolume.class.getClassLoader());
} finally {
_reply.recycle();
_data.recycle();
@@ -1024,9 +1026,9 @@ public interface IMountService extends IInterface {
}
case TRANSACTION_getVolumeList: {
data.enforceInterface(DESCRIPTOR);
String[] result = getVolumeList();
Parcelable[] result = getVolumeList();
reply.writeNoException();
reply.writeStringArray(result);
reply.writeParcelableArray(result, 0);
return true;
}
}
@@ -1207,5 +1209,5 @@ public interface IMountService extends IInterface {
/**
* Returns list of all mountable volumes.
*/
public String[] getVolumeList() throws RemoteException;
public Parcelable[] getVolumeList() throws RemoteException;
}

View File

@@ -19,6 +19,7 @@ package android.os.storage;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -545,12 +546,34 @@ public class StorageManager
* Returns list of all mountable volumes.
* @hide
*/
public String[] getVolumeList() {
public StorageVolume[] getVolumeList() {
try {
return mMountService.getVolumeList();
Parcelable[] list = mMountService.getVolumeList();
if (list == null) return new StorageVolume[0];
int length = list.length;
StorageVolume[] result = new StorageVolume[length];
for (int i = 0; i < length; i++) {
result[i] = (StorageVolume)list[i];
}
return result;
} catch (RemoteException e) {
Log.e(TAG, "Failed to get volume list", e);
return null;
}
}
/**
* Returns list of paths for all mountable volumes.
* @hide
*/
public String[] getVolumePaths() {
StorageVolume[] volumes = getVolumeList();
if (volumes == null) return null;
int count = volumes.length;
String[] paths = new String[count];
for (int i = 0; i < count; i++) {
paths[i] = volumes[i].getPath();
}
return paths;
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2011, 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;
parcelable StorageVolume;

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2011 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.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
/**
* A class representing a storage volume
* @hide
*/
public class StorageVolume implements Parcelable {
private static final String TAG = "StorageVolume";
private final String mPath;
private final String mDescription;
private final boolean mRemovable;
private final boolean mEmulated;
private final int mMtpReserveSpace;
public StorageVolume(String path, String description,
boolean removable, boolean emulated,
int mtpReserveSpace) {
mPath = path;
mDescription = description;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSpace = mtpReserveSpace;
}
/**
* Returns the mount path for the volume.
*
* @return the mount path
*/
public String getPath() {
return mPath;
}
/**
* Returns a user visible description of the volume.
*
* @return the volume description
*/
public String getDescription() {
return mDescription;
}
/**
* Returns true if the volume is removable.
*
* @return is removable
*/
public boolean isRemovable() {
return mRemovable;
}
/**
* Returns true if the volume is emulated.
*
* @return is removable
*/
public boolean isEmulated() {
return mEmulated;
}
/**
* Number of megabytes of space to leave unallocated by MTP.
* MTP will subtract this value from the free space it reports back
* to the host via GetStorageInfo, and will not allow new files to
* be added via MTP if there is less than this amount left free in the storage.
* If MTP has dedicated storage this value should be zero, but if MTP is
* sharing storage with the rest of the system, set this to a positive value
* to ensure that MTP activity does not result in the storage being
* too close to full.
*
* @return MTP reserve space
*/
public int getMtpReserveSpace() {
return mMtpReserveSpace;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
StorageVolume volume = (StorageVolume)obj;
return (mPath.equals(volume.mPath));
}
return false;
}
@Override
public int hashCode() {
return mPath.hashCode();
}
@Override
public String toString() {
return mPath;
}
public static final Parcelable.Creator<StorageVolume> CREATOR =
new Parcelable.Creator<StorageVolume>() {
public StorageVolume createFromParcel(Parcel in) {
String path = in.readString();
String description = in.readString();
int removable = in.readInt();
int emulated = in.readInt();
int mtpReserveSpace = in.readInt();
return new StorageVolume(path, description,
removable == 1, emulated == 1, mtpReserveSpace);
}
public StorageVolume[] newArray(int size) {
return new StorageVolume[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mPath);
parcel.writeString(mDescription);
parcel.writeInt(mRemovable ? 1 : 0);
parcel.writeInt(mEmulated ? 1 : 0);
parcel.writeInt(mMtpReserveSpace);
}
}

View File

@@ -4956,4 +4956,21 @@
<!-- Y coordinate of the icon hot spot. -->
<attr name="hotSpotY" format="float" />
</declare-styleable>
<declare-styleable name="Storage">
<!-- path to mount point for the storage -->
<attr name="mountPoint" format="string" />
<!-- user visible description of the storage -->
<attr name="storageDescription" format="string" />
<!-- true if the storage is the primary external storage -->
<attr name="primary" format="boolean" />
<!-- true if the storage is removable -->
<attr name="removable" format="boolean" />
<!-- true if the storage is emulated via the FUSE sdcard daemon -->
<attr name="emulated" format="boolean" />
<!-- number of megabytes of storage MTP should reserve for free storage
(used for emulated storage that is shared with system's data partition) -->
<attr name="mtpReserve" format="integer" />
</declare-styleable>
</resources>

View File

@@ -2820,4 +2820,13 @@
<string name="action_bar_up_description">Navigate up</string>
<!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
<string name="action_menu_overflow_description">More options</string>
<!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
<string name="storage_internal">Internal Storage</string>
<!-- Storage description for the SD card. [CHAR LIMIT=NONE] -->
<string name="storage_sd_card">SD Card</string>
<!-- Storage description for USB storage. [CHAR LIMIT=NONE] -->
<string name="storage_usb">USB storage</string>
</resources>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2011, 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.
*/
-->
<!-- The <device> element should contain one or more <storage> elements.
Exactly one of these should have the attribute primary="true".
This storage will be the primary external storage and should have mountPoint="/mnt/sdcard".
Each storage should have both a mountPoint and storageDescription attribute.
The following attributes are optional:
primary: (boolean) this storage is the primary external storage
removable: (boolean) this is removable storage (for example, a real SD card)
emulated: (boolean) the storage is emulated via the FUSE sdcard daemon
mtpReserve: (integer) number of megabytes of storage MTP should reserve for free storage
(used for emulated storage that is shared with system's data partition)
A storage should not have both emulated and removable set to true
-->
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_usb"
android:primary="true" />
</StorageList>

View File

@@ -17,6 +17,7 @@
package com.android.server;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.util.XmlUtils;
import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageManagerService;
@@ -29,6 +30,9 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.ObbInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -37,6 +41,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -47,8 +52,14 @@ import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -149,6 +160,8 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
private Context mContext;
private NativeDaemonConnector mConnector;
private final ArrayList<StorageVolume> mVolumes = new ArrayList<StorageVolume>();
private StorageVolume mPrimaryVolume;
private final HashMap<String, String> mVolumeStates = new HashMap<String, String>();
private String mExternalStoragePath;
private PackageManagerService mPms;
@@ -1071,6 +1084,74 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
// Storage list XML tags
private static final String TAG_STORAGE_LIST = "StorageList";
private static final String TAG_STORAGE = "storage";
private void readStorageList(Resources resources) {
int id = com.android.internal.R.xml.storage_list;
XmlResourceParser parser = resources.getXml(id);
AttributeSet attrs = Xml.asAttributeSet(parser);
try {
XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
while (true) {
XmlUtils.nextElement(parser);
String element = parser.getName();
if (element == null) break;
if (TAG_STORAGE.equals(element)) {
TypedArray a = resources.obtainAttributes(attrs,
com.android.internal.R.styleable.Storage);
CharSequence path = a.getText(
com.android.internal.R.styleable.Storage_mountPoint);
CharSequence description = a.getText(
com.android.internal.R.styleable.Storage_storageDescription);
boolean primary = a.getBoolean(
com.android.internal.R.styleable.Storage_primary, false);
boolean removable = a.getBoolean(
com.android.internal.R.styleable.Storage_removable, false);
boolean emulated = a.getBoolean(
com.android.internal.R.styleable.Storage_emulated, false);
int mtpReserve = a.getInt(
com.android.internal.R.styleable.Storage_mtpReserve, 0);
Slog.d(TAG, "got storage path: " + path + " description: " + description +
" primary: " + primary + " removable: " + removable +
" emulated: " + emulated + " mtpReserve: " + mtpReserve);
if (path == null || description == null) {
Slog.e(TAG, "path or description is null in readStorageList");
} else {
StorageVolume volume = new StorageVolume(path.toString(),
description.toString(), removable, emulated, mtpReserve);
if (primary) {
if (mPrimaryVolume == null) {
mPrimaryVolume = volume;
} else {
Slog.e(TAG, "multiple primary volumes in storage list");
}
}
if (mPrimaryVolume == volume) {
// primay volume must be first
mVolumes.add(0, volume);
} else {
mVolumes.add(volume);
}
}
a.recycle();
}
}
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
parser.close();
}
}
/**
* Constructs a new MountService instance
*
@@ -1078,13 +1159,16 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
*/
public MountService(Context context) {
mContext = context;
Resources resources = context.getResources();
readStorageList(resources);
mExternalStoragePath = Environment.getExternalStorageDirectory().getPath();
mEmulateExternalStorage = context.getResources().getBoolean(
com.android.internal.R.bool.config_emulateExternalStorage);
if (mEmulateExternalStorage) {
Slog.d(TAG, "using emulated external storage");
mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
if (mPrimaryVolume != null) {
mExternalStoragePath = mPrimaryVolume.getPath();
mEmulateExternalStorage = mPrimaryVolume.isEmulated();
if (mEmulateExternalStorage) {
Slog.d(TAG, "using emulated external storage");
mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
}
}
// XXX: This will go away soon in favor of IMountServiceObserver
@@ -1756,13 +1840,12 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
public String[] getVolumeList() {
synchronized(mVolumeStates) {
Set<String> volumes = mVolumeStates.keySet();
String[] result = new String[volumes.size()];
int i = 0;
for (String volume : volumes) {
result[i++] = volume;
public Parcelable[] getVolumeList() {
synchronized(mVolumes) {
int size = mVolumes.size();
Parcelable[] result = new Parcelable[size];
for (int i = 0; i < size; i++) {
result[i] = mVolumes.get(i);
}
return result;
}