1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.uicc; 18 19 import android.annotation.IntDef; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import com.android.telephony.Rlog; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.Arrays; 28 import java.util.Objects; 29 30 /** 31 * {@hide} 32 */ 33 public class PlmnActRecord implements Parcelable { 34 private static final String LOG_TAG = "PlmnActRecord"; 35 36 private static final boolean VDBG = false; 37 38 @Retention(RetentionPolicy.SOURCE) 39 @IntDef(flag = true, value = {ACCESS_TECH_UTRAN, ACCESS_TECH_EUTRAN, ACCESS_TECH_GSM, 40 ACCESS_TECH_GSM_COMPACT, ACCESS_TECH_CDMA2000_HRPD, ACCESS_TECH_CDMA2000_1XRTT, 41 ACCESS_TECH_RESERVED}) 42 public @interface AccessTech {} 43 // Values specified in 3GPP 31.102 sec. 4.2.5 44 public static final int ACCESS_TECH_UTRAN = 0x8000; 45 public static final int ACCESS_TECH_EUTRAN = 0x4000; 46 public static final int ACCESS_TECH_GSM = 0x0080; 47 public static final int ACCESS_TECH_GSM_COMPACT = 0x0040; 48 public static final int ACCESS_TECH_CDMA2000_HRPD = 0x0020; 49 public static final int ACCESS_TECH_CDMA2000_1XRTT = 0x0010; 50 public static final int ACCESS_TECH_RESERVED = 0x3F0F; 51 52 public static final int ENCODED_LENGTH = 5; 53 54 public final String plmn; 55 public final int accessTechs; 56 57 /** 58 * Instantiate a PLMN w/ ACT Record 59 */ PlmnActRecord(String plmn, int accessTechs)60 public PlmnActRecord(String plmn, int accessTechs) { 61 this.plmn = plmn; 62 this.accessTechs = accessTechs; 63 } 64 65 /* From 3gpp 31.102 section 4.2.5 66 * Bytes 0-2 bcd-encoded PLMN-ID 67 * Bytes 3-4 bitfield of access technologies 68 */ PlmnActRecord(byte[] bytes, int offset)69 public PlmnActRecord(byte[] bytes, int offset) { 70 if (VDBG) Rlog.v(LOG_TAG, "Creating PlmnActRecord " + offset); 71 this.plmn = IccUtils.bcdPlmnToString(bytes, offset); 72 this.accessTechs = (Byte.toUnsignedInt(bytes[offset + 3]) << 8) 73 | Byte.toUnsignedInt(bytes[offset + 4]); 74 } 75 76 /** 77 * Get a record encoded as per 31.102 section 4.2.5 78 */ getBytes()79 public byte[] getBytes() { 80 byte[] ret = new byte[ENCODED_LENGTH]; 81 IccUtils.stringToBcdPlmn(this.plmn, ret, 0); 82 ret[3] = (byte) (this.accessTechs >> 8); 83 ret[4] = (byte) this.accessTechs; 84 return ret; 85 } 86 accessTechString()87 private String accessTechString() { 88 if (accessTechs == 0) { 89 return "NONE"; 90 } 91 92 StringBuilder sb = new StringBuilder(); 93 if ((accessTechs & ACCESS_TECH_UTRAN) != 0) { 94 sb.append("UTRAN|"); 95 } 96 if ((accessTechs & ACCESS_TECH_EUTRAN) != 0) { 97 sb.append("EUTRAN|"); 98 } 99 if ((accessTechs & ACCESS_TECH_GSM) != 0) { 100 sb.append("GSM|"); 101 } 102 if ((accessTechs & ACCESS_TECH_GSM_COMPACT) != 0) { 103 sb.append("GSM_COMPACT|"); 104 } 105 if ((accessTechs & ACCESS_TECH_CDMA2000_HRPD) != 0) { 106 sb.append("CDMA2000_HRPD|"); 107 } 108 if ((accessTechs & ACCESS_TECH_CDMA2000_1XRTT) != 0) { 109 sb.append("CDMA2000_1XRTT|"); 110 } 111 if ((accessTechs & ACCESS_TECH_RESERVED) != 0) { 112 sb.append(String.format("UNKNOWN:%x|", accessTechs & ACCESS_TECH_RESERVED)); 113 } 114 // Trim the tailing pipe character 115 return sb.substring(0, sb.length() - 1); 116 } 117 118 @Override toString()119 public String toString() { 120 return String.format("{PLMN=%s,AccessTechs=%s}", plmn, accessTechString()); 121 } 122 123 /** 124 * Convenience method for extracting all records from encoded bytes 125 */ getRecords(byte[] recordBytes)126 public static PlmnActRecord[] getRecords(byte[] recordBytes) { 127 if (recordBytes == null || recordBytes.length == 0 128 || recordBytes.length % ENCODED_LENGTH != 0) { 129 Rlog.e(LOG_TAG, "Malformed PlmnActRecord, bytes: " 130 + ((recordBytes != null) ? Arrays.toString(recordBytes) : null)); 131 return null; 132 } 133 int numRecords = recordBytes.length / ENCODED_LENGTH; 134 if (VDBG) Rlog.v(LOG_TAG, "Extracting Logs, count=" + numRecords); 135 136 PlmnActRecord[] records = new PlmnActRecord[numRecords]; 137 138 for(int i = 0; i < numRecords; i++) { 139 records[i] = new PlmnActRecord(recordBytes, i * ENCODED_LENGTH); 140 } 141 return records; 142 } 143 144 // Parcelable Implementation 145 @Override describeContents()146 public int describeContents() { 147 return 0; 148 } 149 150 @Override writeToParcel(Parcel dest, int flags)151 public void writeToParcel(Parcel dest, int flags) { 152 dest.writeString(plmn); 153 dest.writeInt(accessTechs); 154 } 155 156 public static final Parcelable.Creator<PlmnActRecord> CREATOR = 157 new Parcelable.Creator<PlmnActRecord>() { 158 @Override 159 public PlmnActRecord createFromParcel(Parcel source) { 160 return new PlmnActRecord(source.readString(), source.readInt()); 161 } 162 163 @Override 164 public PlmnActRecord[] newArray(int size) { 165 return new PlmnActRecord[size]; 166 } 167 }; 168 169 @Override hashCode()170 public int hashCode() { 171 return Objects.hash(plmn, accessTechs); 172 } 173 174 @Override equals(Object rhs)175 public boolean equals(Object rhs) { 176 if (!(rhs instanceof PlmnActRecord)) return false; 177 178 PlmnActRecord r = (PlmnActRecord) rhs; 179 return plmn.equals(r.plmn) && accessTechs == r.accessTechs; 180 } 181 } 182