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

Commit ddcd076c authored by Hui Wang's avatar Hui Wang Committed by Android (Google) Code Review
Browse files

Merge "Support to search by characteristic for rcs provisioning config" into sc-dev

parents 7c8f0cb8 09632a3a
Loading
Loading
Loading
Loading
+0 −19
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.telephony.ims;

parcelable RcsConfig;
+212 −67
Original line number Diff line number Diff line
@@ -22,10 +22,10 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony.SimInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.telephony.Rlog;

@@ -36,7 +36,9 @@ import org.xmlpull.v1.XmlPullParserFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

@@ -44,27 +46,138 @@ import java.util.zip.GZIPOutputStream;
 * RCS config data and methods to process the config
 * @hide
 */
public final class RcsConfig implements Parcelable {
public final class RcsConfig {
    private static final String LOG_TAG = "RcsConfig";
    private static final boolean DBG = Build.IS_ENG;

    // Tag and attribute defined in RCC.07 A.2
    private static final String TAG_CHARACTERISTIC = "characteristic";
    private static final String TAG_PARM = "parm";
    private static final String ATTRIBUTE_TYPE = "type";
    private static final String ATTRIBUTE_NAME = "name";
    private static final String ATTRIBUTE_VALUE = "value";
    // Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2
    private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";

    private final HashMap<String, String> mValues = new HashMap<>();
    /**
     * Characteristic of the RCS provisioning config
     */
    public static class Characteristic {
        private String mType;
        private final Map<String, String> mParms = new ArrayMap<>();
        private final Set<Characteristic> mSubs = new ArraySet<>();
        private final Characteristic mParent;

        private Characteristic(String type, Characteristic parent) {
            mType = type;
            mParent = parent;
        }

        private String getType() {
            return mType;
        }

        private Map<String, String> getParms() {
            return mParms;
        }

        private Set<Characteristic> getSubs() {
            return mSubs;
        }

        private Characteristic getParent() {
            return mParent;
        }

        private Characteristic getSubByType(String type) {
            if (TextUtils.equals(mType, type)) {
                return this;
            }
            Characteristic result = null;
            for (Characteristic sub : mSubs) {
                result = sub.getSubByType(type);
                if (result != null) {
                    break;
                }
            }
            return result;
        }

        private boolean hasSubByType(String type) {
            return getSubByType(type) != null;
        }

        private String getParmValue(String name) {
            String value = mParms.get(name);
            if (value == null) {
                for (Characteristic sub : mSubs) {
                    value = sub.getParmValue(name);
                    if (value != null) {
                        break;
                    }
                }
            }
            return value;
        }

        boolean hasParm(String name) {
            if (mParms.containsKey(name)) {
                return true;
            }

            for (Characteristic sub : mSubs) {
                if (sub.hasParm(name)) {
                    return true;
                }
            }

    private RcsConfig(HashMap<String, String> values) {
        mValues.putAll(values);
            return false;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("[" + mType + "]: ");
            if (DBG) {
                sb.append(mParms);
            }
            for (Characteristic sub : mSubs) {
                sb.append("\n");
                sb.append(sub.toString().replace("\n", "\n\t"));
            }
            return sb.toString();
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Characteristic)) {
                return false;
            }

            Characteristic o = (Characteristic) obj;

            return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms)
                    && mSubs.equals(o.mSubs);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mType, mParms, mSubs);
        }
    }

    private final Characteristic mRoot;
    private Characteristic mCurrent;
    private final byte[] mData;

    public RcsConfig(byte[] data) throws IllegalArgumentException {
        if (data == null || data.length == 0) {
            throw new IllegalArgumentException("Empty data");
        }
        mRoot = new Characteristic(null, null);
        mCurrent = mRoot;
        mData = data;
        Characteristic current = mRoot;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
@@ -73,36 +186,51 @@ public final class RcsConfig implements Parcelable {
            xpp.setInput(inputStream, null);
            int eventType = xpp.getEventType();
            String tag = null;
            while (eventType != XmlPullParser.END_DOCUMENT) {
            while (eventType != XmlPullParser.END_DOCUMENT && current != null) {
                if (eventType == XmlPullParser.START_TAG) {
                    tag = xpp.getName().trim().toLowerCase();
                    if (tag.equals(TAG_PARM)) {
                    if (TAG_CHARACTERISTIC.equals(tag)) {
                        int count = xpp.getAttributeCount();
                        String type = null;
                        if (count > 0) {
                            for (int i = 0; i < count; i++) {
                                String name = xpp.getAttributeName(i).trim().toLowerCase();
                                if (ATTRIBUTE_TYPE.equals(name)) {
                                    type = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
                                            name).trim().toLowerCase();
                                    break;
                                }
                            }
                        }
                        Characteristic next = new Characteristic(type, current);
                        current.getSubs().add(next);
                        current = next;
                    } else if (TAG_PARM.equals(tag)) {
                        int count = xpp.getAttributeCount();
                        String key = null;
                        String value = null;
                        if (count > 1) {
                            for (int i = 0; i < count; i++) {
                                String name = xpp.getAttributeName(i).trim().toLowerCase();
                                if (name.equals(ATTRIBUTE_NAME)) {
                                if (ATTRIBUTE_NAME.equals(name)) {
                                    key = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
                                            name).trim().toLowerCase();
                                } else if (name.equals(ATTRIBUTE_VALUE)) {
                                } else if (ATTRIBUTE_VALUE.equals(name)) {
                                    value = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
                                            name).trim();
                                }
                            }
                        }
                        if (key != null && value != null) {
                            mValues.put(key, value);
                            current.getParms().put(key, value);
                        }
                    }
                } else if (eventType == XmlPullParser.END_TAG) {
                    tag = null;
                } else if (eventType == XmlPullParser.TEXT) {
                    String value = xpp.getText().trim();
                    if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) {
                        mValues.put(tag, value);
                    tag = xpp.getName().trim().toLowerCase();
                    if (TAG_CHARACTERISTIC.equals(tag)) {
                        current = current.getParent();
                    }
                    tag = null;
                }
                eventType = xpp.next();
            }
@@ -126,8 +254,8 @@ public final class RcsConfig implements Parcelable {
     * @return Returns the config value if it exists, or defaultVal.
     */
    public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) {
        tag = tag.trim().toLowerCase();
        return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal;
        String value = mCurrent.getParmValue(tag.trim().toLowerCase());
        return value != null ?  value : defaultVal;
    }

    /**
@@ -139,9 +267,8 @@ public final class RcsConfig implements Parcelable {
     * @return Returns the config value if it exists and is a valid int, or defaultVal.
     */
    public int getInteger(@NonNull String tag, int defaultVal) {
        tag = tag.trim().toLowerCase();
        try {
            return Integer.parseInt(mValues.get(tag));
            return Integer.parseInt(getString(tag, null));
        } catch (NumberFormatException e) {
            logd("error to getInteger for " + tag + " due to " + e);
        }
@@ -157,11 +284,8 @@ public final class RcsConfig implements Parcelable {
     * @return Returns the config value if it exists, or defaultVal.
     */
    public boolean getBoolean(@NonNull String tag, boolean defaultVal) {
        tag = tag.trim().toLowerCase();
        if (!mValues.containsKey(tag)) {
            return defaultVal;
        }
        return Boolean.parseBoolean(mValues.get(tag));
        String value = getString(tag, null);
        return value != null ? Boolean.parseBoolean(value) : defaultVal;
    }

    /**
@@ -172,7 +296,62 @@ public final class RcsConfig implements Parcelable {
     * @return Returns true if it exists, or false.
     */
    public boolean hasConfig(@NonNull String tag) {
        return mValues.containsKey(tag.trim().toLowerCase());
        return mCurrent.hasParm(tag.trim().toLowerCase());
    }

    /**
     * Return the Characteristic with the given type
     */
    public @Nullable Characteristic getCharacteristic(@NonNull String type) {
        return mCurrent.getSubByType(type.trim().toLowerCase());
    }

    /**
     * Check whether the Characteristic with the given type exists
     */
    public boolean hasCharacteristic(@NonNull String type) {
        return mCurrent.getSubByType(type.trim().toLowerCase()) != null;
    }

    /**
     * Set current Characteristic to given Characteristic
     */
    public void setCurrentCharacteristic(@NonNull Characteristic current) {
        if (current != null) {
            mCurrent = current;
        }
    }

    /**
     * Move current Characteristic to parent layer
     */
    public boolean moveToParent() {
        if (mCurrent.getParent() == null) {
            return false;
        }
        mCurrent = mCurrent.getParent();
        return true;
    }

    /**
     * Move current Characteristic to the root
     */
    public void moveToRoot() {
        mCurrent = mRoot;
    }

    /**
     * Return root Characteristic
     */
    public @NonNull Characteristic getRoot() {
        return mRoot;
    }

    /**
     * Return current Characteristic
     */
    public @NonNull Characteristic getCurrentCharacteristic() {
        return mCurrent;
    }

    /**
@@ -188,12 +367,10 @@ public final class RcsConfig implements Parcelable {
        final StringBuilder sb = new StringBuilder();
        sb.append("[RCS Config]");
        if (DBG) {
            mValues.forEach((t, v) -> {
                sb.append("\n");
                sb.append(t);
                sb.append(" : ");
                sb.append(v);
            });
            sb.append("=== Root ===\n");
            sb.append(mRoot);
            sb.append("=== Current ===\n");
            sb.append(mCurrent);
        }
        return sb.toString();
    }
@@ -206,12 +383,12 @@ public final class RcsConfig implements Parcelable {

        RcsConfig other = (RcsConfig) obj;

        return mValues.equals(other.mValues);
        return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent);
    }

    @Override
    public int hashCode() {
        return mValues.hashCode();
        return Objects.hash(mRoot, mCurrent);
    }

    /**
@@ -302,38 +479,6 @@ public final class RcsConfig implements Parcelable {
        return isCompressed ? data : decompressGzip(data);
    }

    /**
     * {@link Parcelable#writeToParcel}
     */
    public void writeToParcel(@NonNull Parcel out, int flags) {
        out.writeMap(mValues);
    }

    /**
     * {@link Parcelable.Creator}
     *
     */
    public static final @NonNull Parcelable.Creator<RcsConfig>
            CREATOR = new Creator<RcsConfig>() {
                @Override
                public RcsConfig createFromParcel(Parcel in) {
                    HashMap<String, String> values = in.readHashMap(null);
                    return values == null ? null : new RcsConfig(values);
                }

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

    /**
     * {@link Parcelable#describeContents}
     */
    public int describeContents() {
        return 0;
    }

    private static void logd(String msg) {
        Rlog.d(LOG_TAG, msg);
    }