Implement compatibility support for WRITE_SDCARD permission.

Now old applications will automatically be granted it.  Also renamed it from
SDCARD_WRITE to WRITE_SDCARD to be consistent with our other permissions,
and re-arranged how we do targetSdkVersion to actually be usuable for this
kind of stuff.

Note that right now this results in basically all apps being given the
WRITE_SDCARD permission, because their targetSdkVersion is not set.  I will
be dealing with that in a future change.
This commit is contained in:
Dianne Hackborn
2009-05-13 15:06:13 -07:00
parent ba2a3a1b32
commit a96cbb435d
15 changed files with 407 additions and 50 deletions

View File

@@ -870,17 +870,6 @@
visibility="public"
>
</field>
<field name="SDCARD_WRITE"
type="java.lang.String"
transient="false"
volatile="false"
value="&quot;android.permission.SDCARD_WRITE&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="SEND_SMS"
type="java.lang.String"
transient="false"
@@ -1167,6 +1156,17 @@
visibility="public"
>
</field>
<field name="WRITE_SDCARD"
type="java.lang.String"
transient="false"
volatile="false"
value="&quot;android.permission.WRITE_SDCARD&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="WRITE_SECURE_SETTINGS"
type="java.lang.String"
transient="false"
@@ -31824,6 +31824,16 @@
visibility="public"
>
</field>
<field name="targetSdkVersion"
type="int"
transient="false"
volatile="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="taskAffinity"
type="java.lang.String"
transient="false"
@@ -31999,22 +32009,11 @@
visibility="public"
>
</field>
<field name="FLAG_TARGETS_SDK"
type="int"
transient="false"
volatile="false"
value="256"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FLAG_TEST_ONLY"
type="int"
transient="false"
volatile="false"
value="512"
value="256"
static="true"
final="true"
deprecated="not deprecated"
@@ -86002,6 +86001,28 @@
visibility="public"
>
</field>
<field name="CUR_DEVELOPMENT"
type="int"
transient="false"
volatile="false"
value="10000"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="DONUT"
type="int"
transient="false"
volatile="false"
value="10000"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class>
<class name="Bundle"
extends="java.lang.Object"
@@ -139611,6 +139632,17 @@
<implements name="java.lang.annotation.Annotation">
</implements>
</class>
<class name="ViewDebug.FlagToString"
extends="java.lang.Object"
abstract="true"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="java.lang.annotation.Annotation">
</implements>
</class>
<class name="ViewDebug.HierarchyTraceType"
extends="java.lang.Enum"
abstract="false"

View File

@@ -123,13 +123,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* Value for {@link #flags}: this is set of the application has set
* its android:targetSdkVersion to something >= the current SDK version.
*/
public static final int FLAG_TARGETS_SDK = 1<<8;
/**
* Value for {@link #flags}: this is set of the application has set
* its android:targetSdkVersion to something >= the current SDK version.
*/
public static final int FLAG_TEST_ONLY = 1<<9;
public static final int FLAG_TEST_ONLY = 1<<8;
/**
* Flags associated with the application. Any combination of
@@ -137,7 +131,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
* {@link #FLAG_ALLOW_TASK_REPARENTING}
* {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
* {@link #FLAG_TARGETS_SDK}.
* {@link #FLAG_TEST_ONLY}.
*/
public int flags = 0;
@@ -181,6 +175,16 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int[] supportsDensities;
/**
* The minimum SDK version this application targets. It may run on earilier
* versions, but it knows how to work with any new behavior added at this
* version. Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
* if this is a development build and the app is targeting that. You should
* compare that this number is >= the SDK version number at which your
* behavior was introduced.
*/
public int targetSdkVersion;
/**
* When false, indicates that all components within this application are
* considered disabled, regardless of their individually set enabled status.
@@ -200,6 +204,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
pw.println(prefix + "dataDir=" + dataDir);
pw.println(prefix + "targetSdkVersion=" + targetSdkVersion);
pw.println(prefix + "enabled=" + enabled);
pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
@@ -246,6 +251,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
uid = orig.uid;
targetSdkVersion = orig.targetSdkVersion;
enabled = orig.enabled;
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
@@ -276,6 +282,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeStringArray(sharedLibraryFiles);
dest.writeString(dataDir);
dest.writeInt(uid);
dest.writeInt(targetSdkVersion);
dest.writeInt(enabled ? 1 : 0);
dest.writeString(manageSpaceActivityName);
dest.writeInt(descriptionRes);
@@ -305,6 +312,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
sharedLibraryFiles = source.readStringArray();
dataDir = source.readString();
uid = source.readInt();
targetSdkVersion = source.readInt();
enabled = source.readInt() != 0;
manageSpaceActivityName = source.readString();
descriptionRes = source.readInt();

View File

@@ -55,6 +55,30 @@ import java.util.jar.JarFile;
* {@hide}
*/
public class PackageParser {
/** @hide */
public static class NewPermissionInfo {
public final String name;
public final int sdkVersion;
public final int fileVersion;
public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
this.name = name;
this.sdkVersion = sdkVersion;
this.fileVersion = fileVersion;
}
}
/**
* List of new permissions that have been added since 1.0.
* NOTE: These must be declared in SDK version order, with permissions
* added to older SDKs appearing before those added to newer SDKs.
* @hide
*/
public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = new PackageParser.NewPermissionInfo[] {
new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_SDCARD,
android.os.Build.VERSION_CODES.DONUT,
0)
};
private String mArchiveSourcePath;
private String[] mSeparateProcesses;
@@ -616,7 +640,6 @@ public class PackageParser {
final Package pkg = new Package(pkgName);
boolean foundApp = false;
boolean targetsSdk = false;
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
@@ -774,11 +797,10 @@ public class PackageParser {
return null;
}
// If the code matches, it definitely targets this SDK.
targetsSdk = true;
} else if (targetVers >= mSdkVersion) {
// If they have explicitly targeted our current version
// or something after it, then note this.
targetsSdk = true;
pkg.applicationInfo.targetSdkVersion
= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
} else {
pkg.applicationInfo.targetSdkVersion = targetVers;
}
if (minVers > mSdkVersion) {
@@ -824,8 +846,18 @@ public class PackageParser {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
}
if (targetsSdk) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK;
final int NP = PackageParser.NEW_PERMISSIONS.length;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
break;
}
if (!pkg.requestedPermissions.contains(npi.name)) {
Log.i(TAG, "Impliciting adding " + npi.name + " to old pkg "
+ pkg.packageName);
pkg.requestedPermissions.add(npi.name);
}
}
if (pkg.usesLibraries.size() > 0) {

View File

@@ -86,6 +86,12 @@ public class Build {
* increment monotonically with each official platform release.
*/
public static class VERSION_CODES {
/**
* Magic version number for a current development build, which has
* not yet turned into an official release.
*/
public static final int CUR_DEVELOPMENT = 10000;
/**
* October 2008: The original, first, version of Android. Yay!
*/
@@ -98,6 +104,19 @@ public class Build {
* May 2009: Android 1.5.
*/
public static final int CUPCAKE = 3;
/**
* Current work on "Donut" development branch.
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
* <li> They must explicitly request the
* {@link android.Manifest.permission#WRITE_SDCARD} permission to be
* able to modify the contents of the SD card. (Apps targeting
* earlier versions will always request the permission.)
* </ul>
*/
public static final int DONUT = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */

View File

@@ -389,11 +389,11 @@
android:description="@string/permgroupdesc_storage" />
<!-- Allows an application to write to the SD card -->
<permission android:name="android.permission.SDCARD_WRITE"
<permission android:name="android.permission.WRITE_SDCARD"
android:permissionGroup="android.permission-group.STORAGE"
android:label="@string/permlab_sdcardWrite"
android:description="@string/permdesc_sdcardWrite"
android:protectionLevel="normal" />
android:protectionLevel="dangerous" />
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->

View File

@@ -1069,7 +1069,7 @@
user dictionary.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_sdcardWrite">write to SD card</string>
<string name="permlab_sdcardWrite">modify/delete SD card contents</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string>

View File

@@ -54,7 +54,7 @@
<group gid="log" />
</permission>
<permission name="android.permission.SDCARD_WRITE" >
<permission name="android.permission.WRITE_SDCARD" >
<group gid="sdcard_rw" />
</permission>
@@ -84,6 +84,24 @@
others should have a fairly open environment in which to
interact with the system. -->
<!-- Standard permissions granted to the shell. -->
<assign-permission name="android.permission.WRITE_SDCARD" uid="shell" />
<assign-permission name="android.permission.SEND_SMS" uid="shell" />
<assign-permission name="android.permission.CALL_PHONE" uid="shell" />
<assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
<assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
<assign-permission name="android.permission.READ_OWNER_DATA" uid="shell" />
<assign-permission name="android.permission.WRITE_OWNER_DATA" uid="shell" />
<assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
<assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" />
<assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" />
<assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" />
<assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" />
<assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" />
<assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" />
<assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
<assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
<assign-permission name="android.permission.BLUETOOTH" uid="shell" />
<!-- System tool permissions granted to the shell. -->
<assign-permission name="android.permission.GET_TASKS" uid="shell" />
<assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
@@ -114,6 +132,8 @@
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" />
<assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
<assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
<assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
<assign-permission name="android.permission.INSTALL_LOCATION_COLLECTOR" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />

View File

@@ -2828,6 +2828,21 @@ class PackageManagerService extends IPackageManager.Stub {
// we can't add any new permissions to it.
if (!gp.loadedPermissions.contains(perm)) {
allowed = false;
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
// updating the platform).
final int NP = PackageParser.NEW_PERMISSIONS.length;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
if (npi.name.equals(perm)
&& pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
allowed = true;
Log.i(TAG, "Auto-granting WRITE_SDCARD to old pkg "
+ pkg.packageName);
break;
}
}
}
}
if (allowed) {
@@ -3586,7 +3601,9 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
// Re installation failed. Restore old information
// Remove new pkg information
removePackageLI(newPackage, true);
if (newPackage != null) {
removePackageLI(newPackage, true);
}
// Add back the old system package
scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
oldPkgSetting.resourcePath,

View File

@@ -99,6 +99,17 @@ public:
const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; }
void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); }
const char* getMinSdkVersion() const { return mMinSdkVersion; }
void setMinSdkVersion(const char* val) { mMinSdkVersion = val; }
const char* getTargetSdkVersion() const { return mTargetSdkVersion; }
void setTargetSdkVersion(const char* val) { mTargetSdkVersion = val; }
const char* getMaxSdkVersion() const { return mMaxSdkVersion; }
void setMaxSdkVersion(const char* val) { mMaxSdkVersion = val; }
const char* getVersionCode() const { return mVersionCode; }
void setVersionCode(const char* val) { mVersionCode = val; }
const char* getVersionName() const { return mVersionName; }
void setVersionName(const char* val) { mVersionName = val; }
/*
* Set and get the file specification.
*
@@ -151,6 +162,12 @@ private:
android::Vector<const char*> mNoCompressExtensions;
android::Vector<const char*> mResourceSourceDirs;
const char* mMinSdkVersion;
const char* mTargetSdkVersion;
const char* mMaxSdkVersion;
const char* mVersionCode;
const char* mVersionName;
/* file specification */
int mArgc;
char* const* mArgv;

View File

@@ -54,9 +54,10 @@ void usage(void)
" xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName);
fprintf(stderr,
" %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
" [-0 extension [-0 extension ...]] \\\n"
" [-g tolerance] \\\n"
" [-j jarfile] \\\n"
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
" [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
" [--max-sdk-version VAL] [--app-version VAL] \\\n"
" [--app-version-name TEXT] \\\n"
" [-I base-package [-I base-package ...]] \\\n"
" [-A asset-source-dir] [-P public-definitions-file] \\\n"
" [-S resource-sources [-S resource-sources ...]] "
@@ -115,7 +116,17 @@ void usage(void)
" and the first match found (left to right) will take precedence."
" -0 specifies an additional extension for which such files will not\n"
" be stored compressed in the .apk. An empty string means to not\n"
" compress any files at all.\n");
" compress any files at all.\n"
" --min-sdk-version\n"
" inserts android:minSdkVersion in to manifest.\n"
" --target-sdk-version\n"
" inserts android:targetSdkVersion in to manifest.\n"
" --max-sdk-version\n"
" inserts android:maxSdkVersion in to manifest.\n"
" --version-code\n"
" inserts android:versionCode in to manifest.\n"
" --version-name\n"
" inserts android:versionName in to manifest.\n");
}
/*
@@ -339,6 +350,59 @@ int main(int argc, char* const argv[])
bundle.setCompressionMethod(ZipEntry::kCompressStored);
}
break;
case '-':
if (strcmp(cp, "-min-sdk-version") == 0) {
argc--;
argv++;
if (!argc) {
fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
wantUsage = true;
goto bail;
}
bundle.setMinSdkVersion(argv[0]);
} else if (strcmp(cp, "-target-sdk-version") == 0) {
argc--;
argv++;
if (!argc) {
fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
wantUsage = true;
goto bail;
}
bundle.setTargetSdkVersion(argv[0]);
} else if (strcmp(cp, "-max-sdk-version") == 0) {
argc--;
argv++;
if (!argc) {
fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
wantUsage = true;
goto bail;
}
bundle.setMaxSdkVersion(argv[0]);
} else if (strcmp(cp, "-version-code") == 0) {
argc--;
argv++;
if (!argc) {
fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
wantUsage = true;
goto bail;
}
bundle.setVersionCode(argv[0]);
} else if (strcmp(cp, "-version-name") == 0) {
argc--;
argv++;
if (!argc) {
fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
wantUsage = true;
goto bail;
}
bundle.setVersionName(argv[0]);
} else {
fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
wantUsage = true;
goto bail;
}
cp += strlen(cp) - 1;
break;
default:
fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
wantUsage = true;

View File

@@ -495,6 +495,58 @@ static void applyFileOverlay(const sp<AaptAssets>& assets,
return;
}
void addTagAttribute(const sp<XMLNode>& node, const char* ns8,
const char* attr8, const char* value)
{
if (value == NULL) {
return;
}
const String16 ns(ns8);
const String16 attr(attr8);
if (node->getAttribute(ns, attr) != NULL) {
fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
String8(attr).string(), String8(ns).string());
return;
}
node->addAttribute(ns, attr, String16(value));
}
status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
{
root = root->searchElement(String16(), String16("manifest"));
if (root == NULL) {
fprintf(stderr, "No <manifest> tag.\n");
return UNKNOWN_ERROR;
}
addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
bundle->getVersionCode());
addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
bundle->getVersionName());
if (bundle->getMinSdkVersion() != NULL
|| bundle->getTargetSdkVersion() != NULL
|| bundle->getMaxSdkVersion() != NULL) {
sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
if (vers == NULL) {
vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
root->insertChildAt(vers, 0);
}
addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
bundle->getMinSdkVersion());
addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion",
bundle->getTargetSdkVersion());
addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion",
bundle->getMaxSdkVersion());
}
return NO_ERROR;
}
#define ASSIGN_IT(n) \
do { \
ssize_t index = resources->indexOfKey(String8(#n)); \
@@ -1013,7 +1065,15 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
// Generate final compiled manifest file.
manifestFile->clearData();
err = compileXmlFile(assets, manifestFile, &table);
sp<XMLNode> manifestTree = XMLNode::parse(manifestFile);
if (manifestTree == NULL) {
return UNKNOWN_ERROR;
}
err = massageManifest(bundle, manifestTree);
if (err < NO_ERROR) {
return err;
}
err = compileXmlFile(assets, manifestTree, manifestFile, &table);
if (err < NO_ERROR) {
return err;
}

View File

@@ -23,6 +23,16 @@ status_t compileXmlFile(const sp<AaptAssets>& assets,
if (root == NULL) {
return UNKNOWN_ERROR;
}
return compileXmlFile(assets, root, target, table, options);
}
status_t compileXmlFile(const sp<AaptAssets>& assets,
const sp<XMLNode>& root,
const sp<AaptFile>& target,
ResourceTable* table,
int options)
{
if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
root->removeWhitespace(true, NULL);
} else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -1307,7 +1317,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
} else if (id != 0) {
if (id == 127) {
if (mHaveAppPackage) {
fprintf(stderr, "Included resource have two application packages!\n");
fprintf(stderr, "Included resources have two application packages!\n");
return UNKNOWN_ERROR;
}
mHaveAppPackage = true;

View File

@@ -15,6 +15,7 @@
using namespace std;
class XMLNode;
class ResourceTable;
enum {
@@ -34,6 +35,12 @@ status_t compileXmlFile(const sp<AaptAssets>& assets,
ResourceTable* table,
int options = XML_COMPILE_STANDARD_RESOURCE);
status_t compileXmlFile(const sp<AaptAssets>& assets,
const sp<XMLNode>& xmlTree,
const sp<AaptFile>& target,
ResourceTable* table,
int options = XML_COMPILE_STANDARD_RESOURCE);
status_t compileResourceFile(Bundle* bundle,
const sp<AaptAssets>& assets,
const sp<AaptFile>& in,

View File

@@ -524,12 +524,30 @@ const Vector<sp<XMLNode> >& XMLNode::getChildren() const
return mChildren;
}
const String8& XMLNode::getFilename() const
{
return mFilename;
}
const Vector<XMLNode::attribute_entry>&
XMLNode::getAttributes() const
{
return mAttributes;
}
const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns,
const String16& name) const
{
for (size_t i=0; i<mAttributes.size(); i++) {
const attribute_entry& ae(mAttributes.itemAt(i));
if (ae.ns == ns && ae.name == name) {
return &ae;
}
}
return NULL;
}
const String16& XMLNode::getCData() const
{
return mChars;
@@ -550,6 +568,38 @@ int32_t XMLNode::getEndLineNumber() const
return mEndLineNumber;
}
sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName)
{
if (getType() == XMLNode::TYPE_ELEMENT
&& mNamespaceUri == tagNamespace
&& mElementName == tagName) {
return this;
}
for (size_t i=0; i<mChildren.size(); i++) {
sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName);
if (found != NULL) {
return found;
}
}
return NULL;
}
sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName)
{
for (size_t i=0; i<mChildren.size(); i++) {
sp<XMLNode> child = mChildren.itemAt(i);
if (child->getType() == XMLNode::TYPE_ELEMENT
&& child->mNamespaceUri == tagNamespace
&& child->mElementName == tagName) {
return child;
}
}
return NULL;
}
status_t XMLNode::addChild(const sp<XMLNode>& child)
{
if (getType() == TYPE_CDATA) {
@@ -561,6 +611,17 @@ status_t XMLNode::addChild(const sp<XMLNode>& child)
return NO_ERROR;
}
status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index)
{
if (getType() == TYPE_CDATA) {
SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
return UNKNOWN_ERROR;
}
//printf("Adding child %p to parent %p\n", child.get(), this);
mChildren.insertAt(child, index);
return NO_ERROR;
}
status_t XMLNode::addAttribute(const String16& ns, const String16& name,
const String16& value)
{

View File

@@ -68,6 +68,8 @@ public:
const String16& getElementName() const;
const Vector<sp<XMLNode> >& getChildren() const;
const String8& getFilename() const;
struct attribute_entry {
attribute_entry() : index(~(uint32_t)0), nameResId(0)
{
@@ -91,6 +93,8 @@ public:
const Vector<attribute_entry>& getAttributes() const;
const attribute_entry* getAttribute(const String16& ns, const String16& name) const;
const String16& getCData() const;
const String16& getComment() const;
@@ -98,8 +102,14 @@ public:
int32_t getStartLineNumber() const;
int32_t getEndLineNumber() const;
sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName);
sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName);
status_t addChild(const sp<XMLNode>& child);
status_t insertChildAt(const sp<XMLNode>& child, size_t index);
status_t addAttribute(const String16& ns, const String16& name,
const String16& value);