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

Commit 47a7426d authored by Holly Jiuyu Sun's avatar Holly Jiuyu Sun
Browse files

Add dependencies of EuiccCard.

Include EuiccNotification and EuiccRat.
Change EuiccRat to Parcelable.

Bug: 38206971
Test: unit test
Change-Id: Ifbe01e64b92ab0b042779487df4dd99159c5e3b8
parent 999d998f
Loading
Loading
Loading
Loading
+179 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.telephony.euicc;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;

/**
 * This represents a signed notification which is defined in SGP.22. It can be either a profile
 * installation result or a notification generated for profile operations (e.g., enabling,
 * disabling, or deleting).
 *
 * @hide
 *
 * TODO(b/35851809): Make this a @SystemApi.
 */
public class EuiccNotification implements Parcelable {
    /** Event */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = { "EVENT_" }, value = {
            EVENT_INSTALL,
            EVENT_ENABLE,
            EVENT_DISABLE,
            EVENT_DELETE
    })
    public @interface Event {}

    /** A profile is downloaded and installed. */
    public static final int EVENT_INSTALL = 1;

    /** A profile is enabled. */
    public static final int EVENT_ENABLE = 1 << 1;

    /** A profile is disabled. */
    public static final int EVENT_DISABLE = 1 << 2;

    /** A profile is deleted. */
    public static final int EVENT_DELETE = 1 << 3;

    /** Value of the bits of all above events */
    @Event
    public static final int ALL_EVENTS =
            EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE;

    private final int mSeq;
    private final String mTargetAddr;
    @Event private final int mEvent;
    @Nullable private final byte[] mData;

    /**
     * Creates an instance.
     *
     * @param seq The sequence number of this notification.
     * @param targetAddr The target server where to send this notification.
     * @param event The event which causes this notification.
     * @param data The data which needs to be sent to the target server. This can be null for
     *     building a list of notification metadata without data.
     */
    public EuiccNotification(int seq, String targetAddr, @Event int event, @Nullable byte[] data) {
        mSeq = seq;
        mTargetAddr = targetAddr;
        mEvent = event;
        mData = data;
    }

    /** @return The sequence number of this notification. */
    public int getSeq() {
        return mSeq;
    }

    /** @return The target server address where this notification should be sent to. */
    public String getTargetAddr() {
        return mTargetAddr;
    }

    /** @return The event of this notification. */
    @Event
    public int getEvent() {
        return mEvent;
    }

    /** @return The notification data which needs to be sent to the target server. */
    @Nullable
    public byte[] getData() {
        return mData;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        EuiccNotification that = (EuiccNotification) obj;
        return mSeq == that.mSeq
                && Objects.equals(mTargetAddr, that.mTargetAddr)
                && mEvent == that.mEvent
                && Arrays.equals(mData, that.mData);
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + mSeq;
        result = 31 * result + Objects.hashCode(mTargetAddr);
        result = 31 * result + mEvent;
        result = 31 * result + Arrays.hashCode(mData);
        return result;
    }

    @Override
    public String toString() {
        return "EuiccNotification (seq="
                + mSeq
                + ", targetAddr="
                + mTargetAddr
                + ", event="
                + mEvent
                + ", data="
                + (mData == null ? "null" : "byte[" + mData.length + "]")
                + ")";
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mSeq);
        dest.writeString(mTargetAddr);
        dest.writeInt(mEvent);
        dest.writeByteArray(mData);
    }

    private EuiccNotification(Parcel source) {
        mSeq = source.readInt();
        mTargetAddr = source.readString();
        mEvent = source.readInt();
        mData = source.createByteArray();
    }

    public static final Creator<EuiccNotification> CREATOR =
            new Creator<EuiccNotification>() {
                @Override
                public EuiccNotification createFromParcel(Parcel source) {
                    return new EuiccNotification(source);
                }

                @Override
                public EuiccNotification[] newArray(int size) {
                    return new EuiccNotification[size];
                }
            };
}
+259 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.telephony.euicc;

import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
import android.service.euicc.EuiccProfileInfo;
import android.text.TextUtils;

import com.android.internal.annotations.VisibleForTesting;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;

/**
 * This represents the RAT (Rules Authorisation Table) stored on eUICC.
 *
 * @hide
 *
 * TODO(b/35851809): Make this a @SystemApi.
 */
public final class EuiccRat implements Parcelable {
    /** Profile policy rule flags */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
            POLICY_RULE_FLAG_CONSENT_REQUIRED
    })
    public @interface PolicyRuleFlag {}

    /** User consent is required to install the profile. */
    public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1;

    private final int[] mPolicyRules;
    private final CarrierIdentifier[][] mCarrierIds;
    private final int[] mPolicyRuleFlags;

    /** This is used to build new {@link EuiccRat} instance. */
    public static final class Builder {
        private int[] mPolicyRules;
        private CarrierIdentifier[][] mCarrierIds;
        private int[] mPolicyRuleFlags;
        private int mPosition;

        /**
         * Creates a new builder.
         *
         * @param ruleNum The number of authorisation rules in the table.
         */
        public Builder(int ruleNum) {
            mPolicyRules = new int[ruleNum];
            mCarrierIds = new CarrierIdentifier[ruleNum][];
            mPolicyRuleFlags = new int[ruleNum];
        }

        /**
         * Builds the RAT instance. This builder should not be used anymore after this method is
         * called, otherwise {@link NullPointerException} will be thrown.
         */
        public EuiccRat build() {
            if (mPosition != mPolicyRules.length) {
                throw new IllegalStateException(
                        "Not enough rules are added, expected: "
                                + mPolicyRules.length
                                + ", added: "
                                + mPosition);
            }
            return new EuiccRat(mPolicyRules, mCarrierIds, mPolicyRuleFlags);
        }

        /**
         * Adds an authorisation rule.
         *
         * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size
         *     this table.
         */
        public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) {
            if (mPosition >= mPolicyRules.length) {
                throw new ArrayIndexOutOfBoundsException(mPosition);
            }
            mPolicyRules[mPosition] = policyRules;
            mCarrierIds[mPosition] = carrierId;
            mPolicyRuleFlags[mPosition] = policyRuleFlags;
            mPosition++;
            return this;
        }
    }

    /**
     * @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The
     *     character 'E' is used as a wild char to match any digit.
     * @param mcc A 2-character or 3-character string which can be either MCC or MNC.
     * @return Whether the {@code mccRule} matches {@code mcc}.
     *
     * @hide
     */
    @VisibleForTesting
    public static boolean match(String mccRule, String mcc) {
        if (mccRule.length() < mcc.length()) {
            return false;
        }
        for (int i = 0; i < mccRule.length(); i++) {
            // 'E' is the wild char to match any digit.
            if (mccRule.charAt(i) == 'E'
                    || (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) {
                continue;
            }
            return false;
        }
        return true;
    }

    private EuiccRat(int[] policyRules, CarrierIdentifier[][] carrierIds, int[] policyRuleFlags) {
        mPolicyRules = policyRules;
        mCarrierIds = carrierIds;
        mPolicyRuleFlags = policyRuleFlags;
    }

    /**
     * Finds the index of the first authorisation rule matching the given policy and carrier id. If
     * the returned index is not negative, the carrier is allowed to apply this policy to its
     * profile.
     *
     * @param policy The policy rule.
     * @param carrierId The carrier id.
     * @return The index of authorization rule. If no rule is found, -1 will be returned.
     */
    public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) {
        for (int i = 0; i < mPolicyRules.length; i++) {
            if ((mPolicyRules[i] & policy) == 0) {
                continue;
            }
            CarrierIdentifier[] carrierIds = mCarrierIds[i];
            if (carrierIds == null || carrierIds.length == 0) {
                continue;
            }
            for (int j = 0; j < carrierIds.length; j++) {
                CarrierIdentifier ruleCarrierId = carrierIds[j];
                if (!match(ruleCarrierId.getMcc(), carrierId.getMcc())
                        || !match(ruleCarrierId.getMnc(), carrierId.getMnc())) {
                    continue;
                }
                String gid = ruleCarrierId.getGid1();
                if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) {
                    continue;
                }
                gid = ruleCarrierId.getGid2();
                if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) {
                    continue;
                }
                return i;
            }
        }
        return -1;
    }

    /**
     * Tests if the entry in the table has the given policy rule flag.
     *
     * @param index The index of the entry.
     * @param flag The policy rule flag to be tested.
     * @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the
     *     size of this table.
     */
    public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) {
        if (index < 0 || index >= mPolicyRules.length) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        return (mPolicyRuleFlags[index] & flag) != 0;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeIntArray(mPolicyRules);
        for (CarrierIdentifier[] ids : mCarrierIds) {
            dest.writeTypedArray(ids, flags);
        }
        dest.writeIntArray(mPolicyRuleFlags);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        EuiccRat that = (EuiccRat) obj;
        if (mCarrierIds.length != that.mCarrierIds.length) {
            return false;
        }
        for (int i = 0; i < mCarrierIds.length; i++) {
            CarrierIdentifier[] carrierIds = mCarrierIds[i];
            CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i];
            if (carrierIds != null && thatCarrierIds != null) {
                if (carrierIds.length != thatCarrierIds.length) {
                    return false;
                }
                for (int j = 0; j < carrierIds.length; j++) {
                    if (!carrierIds[j].equals(thatCarrierIds[j])) {
                        return false;
                    }
                }
                continue;
            } else if (carrierIds == null && thatCarrierIds == null) {
                continue;
            }
            return false;
        }

        return Arrays.equals(mPolicyRules, that.mPolicyRules)
                && Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags);
    }

    private EuiccRat(Parcel source) {
        mPolicyRules = source.createIntArray();
        int len = mPolicyRules.length;
        mCarrierIds = new CarrierIdentifier[len][];
        for (int i = 0; i < len; i++) {
            mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR);
        }
        mPolicyRuleFlags = source.createIntArray();
    }

    public static final Creator<EuiccRat> CREATOR =
            new Creator<EuiccRat>() {
                @Override
                public EuiccRat createFromParcel(Parcel source) {
                    return new EuiccRat(source);
                }

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