Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2d6cd58 authored by Todd Kennedy's avatar Todd Kennedy Committed by Android (Google) Code Review
Browse files

Merge "Add PackageManager.Property class"

parents aa857a44 c26e1f91
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -12345,6 +12345,23 @@ package android.content.pm {
    ctor public PackageManager.NameNotFoundException(String);
  }
  public static final class PackageManager.Property implements android.os.Parcelable {
    method public int describeContents();
    method public boolean getBoolean();
    method public float getFloat();
    method public int getInteger();
    method @NonNull public String getName();
    method public int getResourceId();
    method @Nullable public String getString();
    method public boolean isBoolean();
    method public boolean isFloat();
    method public boolean isInteger();
    method public boolean isResourceId();
    method public boolean isString();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageManager.Property> CREATOR;
  }
  @Deprecated public class PackageStats implements android.os.Parcelable {
    ctor @Deprecated public PackageStats(String);
    ctor @Deprecated public PackageStats(android.os.Parcel);
+210 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -75,6 +77,7 @@ import android.permission.PermissionManager;
import android.util.AndroidException;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;

import dalvik.system.VMRuntime;
@@ -115,6 +118,213 @@ public abstract class PackageManager {
        }
    }

    /**
     * A property value set within the manifest.
     * <p>
     * The value of a property will only have a single type, as defined by
     * the property itself.
     */
    public static final class Property implements Parcelable {
        private static final int TYPE_BOOLEAN = 1;
        private static final int TYPE_FLOAT = 2;
        private static final int TYPE_INTEGER = 3;
        private static final int TYPE_RESOURCE = 4;
        private static final int TYPE_STRING = 5;
        private final String mName;
        private boolean mBooleanValue;
        private float mFloatValue;
        private int mIntegerValue;
        private String mStringValue;
        private final int mType;

        /** @hide */
        @VisibleForTesting
        public Property(@NonNull String name, int type) {
            assert name != null;
            assert type >= TYPE_BOOLEAN && type <= TYPE_STRING;
            this.mName = name;
            this.mType = type;
        }
        /** @hide */
        public Property(@NonNull String name, boolean value) {
            this(name, TYPE_BOOLEAN);
            mBooleanValue = value;
        }
        /** @hide */
        public Property(@NonNull String name, float value) {
            this(name, TYPE_FLOAT);
            mFloatValue = value;
        }
        /** @hide */
        public Property(@NonNull String name, int value, boolean isResource) {
            this(name, isResource ? TYPE_RESOURCE : TYPE_INTEGER);
            mIntegerValue = value;
        }
        /** @hide */
        public Property(@NonNull String name, String value) {
            this(name, TYPE_STRING);
            mStringValue = value;
        }

        /** @hide */
        @VisibleForTesting
        public int getType() {
            return mType;
        }

        /**
         * Returns the name of the property.
         */
        @NonNull public String getName() {
            return mName;
        }

        /**
         * Returns the boolean value set for the property.
         * <p>If the property is not of a boolean type, returns {@code false}.
         */
        public boolean getBoolean() {
            return mBooleanValue;
        }

        /**
         * Returns {@code true} if the property is a boolean type. Otherwise {@code false}.
         */
        public boolean isBoolean() {
            return mType == TYPE_BOOLEAN;
        }

        /**
         * Returns the float value set for the property.
         * <p>If the property is not of a float type, returns {@code 0.0}.
         */
        public float getFloat() {
            return mFloatValue;
        }

        /**
         * Returns {@code true} if the property is a float type. Otherwise {@code false}.
         */
        public boolean isFloat() {
            return mType == TYPE_FLOAT;
        }

        /**
         * Returns the integer value set for the property.
         * <p>If the property is not of an integer type, returns {@code 0}.
         */
        public int getInteger() {
            return mType == TYPE_INTEGER ? mIntegerValue : 0;
        }

        /**
         * Returns {@code true} if the property is an integer type. Otherwise {@code false}.
         */
        public boolean isInteger() {
            return mType == TYPE_INTEGER;
        }

        /**
         * Returns the a resource id set for the property.
         * <p>If the property is not of a resource id type, returns {@code 0}.
         */
        public int getResourceId() {
            return mType == TYPE_RESOURCE ? mIntegerValue : 0;
        }

        /**
         * Returns {@code true} if the property is a resource id type. Otherwise {@code false}.
         */
        public boolean isResourceId() {
            return mType == TYPE_RESOURCE;
        }

        /**
         * Returns the a String value set for the property.
         * <p>If the property is not a String type, returns {@code null}.
         */
        @Nullable public String getString() {
            return mStringValue;
        }

        /**
         * Returns {@code true} if the property is a String type. Otherwise {@code false}.
         */
        public boolean isString() {
            return mType == TYPE_STRING;
        }

        /**
         * Adds a mapping from the given key to this property's value in the provided
         * {@link android.os.Bundle}. If the provided {@link android.os.Bundle} is
         * {@code null}, creates a new {@link android.os.Bundle}.
         * @hide
         */
        public Bundle toBundle(Bundle outBundle) {
            final Bundle b = outBundle == null ? new Bundle() : outBundle;
            if (mType == TYPE_BOOLEAN) {
                b.putBoolean(mName, mBooleanValue);
            } else if (mType == TYPE_FLOAT) {
                b.putFloat(mName, mFloatValue);
            } else if (mType == TYPE_INTEGER) {
                b.putInt(mName, mIntegerValue);
            } else if (mType == TYPE_RESOURCE) {
                b.putInt(mName, mIntegerValue);
            } else if (mType == TYPE_STRING) {
                b.putString(mName, mStringValue);
            }
            return b;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeString(mName);
            dest.writeInt(mType);
            if (mType == TYPE_BOOLEAN) {
                dest.writeBoolean(mBooleanValue);
            } else if (mType == TYPE_FLOAT) {
                dest.writeFloat(mFloatValue);
            } else if (mType == TYPE_INTEGER) {
                dest.writeInt(mIntegerValue);
            } else if (mType == TYPE_RESOURCE) {
                dest.writeInt(mIntegerValue);
            } else if (mType == TYPE_STRING) {
                dest.writeString(mStringValue);
            }
        }

        @NonNull
        public static final Creator<Property> CREATOR = new Creator<Property>() {
            @Override
            public Property createFromParcel(@NonNull Parcel source) {
                final String name = source.readString();
                final int type = source.readInt();
                if (type == TYPE_BOOLEAN) {
                    return new Property(name, source.readBoolean());
                } else if (type == TYPE_FLOAT) {
                    return new Property(name, source.readFloat());
                } else if (type == TYPE_INTEGER) {
                    return new Property(name, source.readInt(), false);
                } else if (type == TYPE_RESOURCE) {
                    return new Property(name, source.readInt(), true);
                } else if (type == TYPE_STRING) {
                    return new Property(name, source.readString());
                }
                return null;
            }

            @Override
            public Property[] newArray(int size) {
                return new Property[size];
            }
        };
    }

    /**
     * Listener for changes in permissions granted to a UID.
     *
+32 −0
Original line number Diff line number Diff line
@@ -2834,6 +2834,38 @@
        <attr name="resource" format="reference" />
    </declare-styleable>

    <!-- The <code>property</code> tag is used to attach additional data that can
         be supplied to the parent component. A component element can contain any
         number of <code>property</code> subelements. Valid names are any of the
         <code>PROPERTY_</code> constants defined in the
         {@link android.content.pm.PackageManager PackageManager} class. Values
         are obtained using the appropriate method on the
         {@link android.content.pm.PackageManager.Property PackageManager.Property} class.
         <p>Ordinary values are specified through the value attribute. Resource IDs are
         specified through the resource attribute.
         <p>It is invalid to specify both a value and resource attributes. -->
    <declare-styleable name="AndroidManifestProperty"
         parent="AndroidManifestApplication
                 AndroidManifestActivity
                 AndroidManifestReceiver
                 AndroidManifestProvider
                 AndroidManifestService">
        <attr name="name" />
        <!-- Concrete value to assign to this property.
             The data can later be retrieved from the property object
             through
             {@link android.content.pm.PackageManager.Property#getString Property.getString},
             {@link android.content.pm.PackageManager.Property#getInteger Property.getInteger},
             {@link android.content.pm.PackageManager.Property#getBoolean Property.getBoolean},
             or {@link android.content.pm.PackageManager.Property#getFloat Property.getFloat}
             depending on the type used here. -->
        <attr name="value" />
        <!-- The resource identifier to assign to this property.
             The resource identifier can later be retrieved from the property object through
             {@link android.content.pm.PackageManager.Property#getResourceId Property.getResourceId}. -->
        <attr name="resource" />
    </declare-styleable>

    <!-- The <code>intent-filter</code> tag is used to construct an
         {@link android.content.IntentFilter} object that will be used
         to determine which component can handle a particular
+169 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.content.pm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.content.pm.PackageManager.Property;
import android.os.Bundle;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class PackageManagerPropertyTests {

    @Test
    public void testBooleanProperty() throws Exception {
        final Property p = new Property("booleanProperty", true);
        assertTrue(p.isBoolean());
        assertFalse(p.isFloat());
        assertFalse(p.isInteger());
        assertFalse(p.isResourceId());
        assertFalse(p.isString());
        assertTrue(p.getBoolean());
        assertEquals(0.0f, p.getFloat(), 0.0f);
        assertEquals(0, p.getInteger());
        assertEquals(0, p.getResourceId());
        assertEquals(null, p.getString());
    }

    @Test
    public void testBooleanPropertyToBundle() throws Exception {
        final Bundle b = new Property("booleanProperty", true).toBundle(null);
        assertTrue(b.getBoolean("booleanProperty"));
    }

    @Test
    public void testFloatProperty() throws Exception {
        final Property p = new Property("floatProperty", 3.14f);
        assertFalse(p.isBoolean());
        assertTrue(p.isFloat());
        assertFalse(p.isInteger());
        assertFalse(p.isResourceId());
        assertFalse(p.isString());
        assertFalse(p.getBoolean());
        assertEquals(3.14f, p.getFloat(), 0.0f);
        assertEquals(0, p.getInteger());
        assertEquals(0, p.getResourceId());
        assertEquals(null, p.getString());
    }

    @Test
    public void testFloatPropertyToBundle() throws Exception {
        final Bundle b = new Property("floatProperty", 3.14f).toBundle(null);
        assertEquals(3.14f, b.getFloat("floatProperty"), 0.0f);
    }

    @Test
    public void testIntegerProperty() throws Exception {
        final Property p = new Property("integerProperty", 42, false);
        assertFalse(p.isBoolean());
        assertFalse(p.isFloat());
        assertTrue(p.isInteger());
        assertFalse(p.isResourceId());
        assertFalse(p.isString());
        assertFalse(p.getBoolean());
        assertEquals(0.0f, p.getFloat(), 0.0f);
        assertEquals(42, p.getInteger());
        assertEquals(0, p.getResourceId());
        assertEquals(null, p.getString());
    }

    @Test
    public void testIntegerPropertyToBundle() throws Exception {
        final Bundle b = new Property("integerProperty", 42, false).toBundle(null);
        assertEquals(42, b.getInt("integerProperty"));
    }

    @Test
    public void testResourceProperty() throws Exception {
        final Property p = new Property("resourceProperty", 0x7f010001, true);
        assertFalse(p.isBoolean());
        assertFalse(p.isFloat());
        assertFalse(p.isInteger());
        assertTrue(p.isResourceId());
        assertFalse(p.isString());
        assertFalse(p.getBoolean());
        assertEquals(0.0f, p.getFloat(), 0.0f);
        assertEquals(0, p.getInteger());
        assertEquals(0x7f010001, p.getResourceId());
        assertEquals(null, p.getString());
    }

    @Test
    public void testResourcePropertyToBundle() throws Exception {
        final Bundle b = new Property("resourceProperty", 0x7f010001, true).toBundle(null);
        assertEquals(0x7f010001, b.getInt("resourceProperty"));
    }

    @Test
    public void testStringProperty() throws Exception {
        final Property p = new Property("stringProperty", "koala");
        assertFalse(p.isBoolean());
        assertFalse(p.isFloat());
        assertFalse(p.isInteger());
        assertFalse(p.isResourceId());
        assertTrue(p.isString());
        assertFalse(p.getBoolean());
        assertEquals(0.0f, p.getFloat(), 0.0f);
        assertEquals(0, p.getInteger());
        assertEquals(0, p.getResourceId());
        assertEquals("koala", p.getString());
    }

    @Test
    public void testStringPropertyToBundle() throws Exception {
        final Bundle b = new Property("stringProperty", "koala").toBundle(null);
        assertEquals("koala", b.getString("stringProperty"));
    }

    @Test
    public void testProperty_invalidName() throws Exception {
        try {
            final Property p = new Property(null, 1);
            fail("expected assertion error");
        } catch (AssertionError expected) {
        }
    }

    @Test
    public void testProperty_invalidType() throws Exception {
        try {
            final Property p = new Property(null, 0);
            fail("expected assertion error");
        } catch (AssertionError expected) {
        }

        try {
            final Property p = new Property(null, 6);
            fail("expected assertion error");
        } catch (AssertionError expected) {
        }

        try {
            final Property p = new Property(null, -1);
            fail("expected assertion error");
        } catch (AssertionError expected) {
        }
    }
}