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 import android.telephony.Rlog; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.util.Arrays; 27 import java.util.Objects; 28 29 /** 30 * {@hide} 31 */ 32 public class PlmnActRecord implements Parcelable { 33 private static final String LOG_TAG = "PlmnActRecord"; 34 35 private static final boolean VDBG = false; 36 37 @Retention(RetentionPolicy.SOURCE) 38 @IntDef(flag = true, value = {ACCESS_TECH_UTRAN, ACCESS_TECH_EUTRAN, ACCESS_TECH_GSM, 39 ACCESS_TECH_GSM_COMPACT, ACCESS_TECH_CDMA2000_HRPD, ACCESS_TECH_CDMA2000_1XRTT, 40 ACCESS_TECH_RESERVED}) 41 public @interface AccessTech {} 42 // Values specified in 3GPP 31.102 sec. 4.2.5 43 public static final int ACCESS_TECH_UTRAN = 0x8000; 44 public static final int ACCESS_TECH_EUTRAN = 0x4000; 45 public static final int ACCESS_TECH_GSM = 0x0080; 46 public static final int ACCESS_TECH_GSM_COMPACT = 0x0040; 47 public static final int ACCESS_TECH_CDMA2000_HRPD = 0x0020; 48 public static final int ACCESS_TECH_CDMA2000_1XRTT = 0x0010; 49 public static final int ACCESS_TECH_RESERVED = 0x3F0F; 50 51 public static final int ENCODED_LENGTH = 5; 52 53 public final String plmn; 54 public final int accessTechs; 55 56 /** 57 * Instantiate a PLMN w/ ACT Record 58 */ PlmnActRecord(String plmn, int accessTechs)59 public PlmnActRecord(String plmn, int accessTechs) { 60 this.plmn = plmn; 61 this.accessTechs = accessTechs; 62 } 63 64 /* From 3gpp 31.102 section 4.2.5 65 * Bytes 0-2 bcd-encoded PLMN-ID 66 * Bytes 3-4 bitfield of access technologies 67 */ PlmnActRecord(byte[] bytes, int offset)68 public PlmnActRecord(byte[] bytes, int offset) { 69 if (VDBG) Rlog.v(LOG_TAG, "Creating PlmnActRecord " + offset); 70 this.plmn = IccUtils.bcdPlmnToString(bytes, offset); 71 this.accessTechs = (Byte.toUnsignedInt(bytes[offset + 3]) << 8) 72 | Byte.toUnsignedInt(bytes[offset + 4]); 73 } 74 75 /** 76 * Get a record encoded as per 31.102 section 4.2.5 77 */ getBytes()78 public byte[] getBytes() { 79 byte[] ret = new byte[ENCODED_LENGTH]; 80 IccUtils.stringToBcdPlmn(this.plmn, ret, 0); 81 ret[3] = (byte) (this.accessTechs >> 8); 82 ret[4] = (byte) this.accessTechs; 83 return ret; 84 } 85 accessTechString()86 private String accessTechString() { 87 if (accessTechs == 0) { 88 return "NONE"; 89 } 90 91 StringBuilder sb = new StringBuilder(); 92 if ((accessTechs & ACCESS_TECH_UTRAN) != 0) { 93 sb.append("UTRAN|"); 94 } 95 if ((accessTechs & ACCESS_TECH_EUTRAN) != 0) { 96 sb.append("EUTRAN|"); 97 } 98 if ((accessTechs & ACCESS_TECH_GSM) != 0) { 99 sb.append("GSM|"); 100 } 101 if ((accessTechs & ACCESS_TECH_GSM_COMPACT) != 0) { 102 sb.append("GSM_COMPACT|"); 103 } 104 if ((accessTechs & ACCESS_TECH_CDMA2000_HRPD) != 0) { 105 sb.append("CDMA2000_HRPD|"); 106 } 107 if ((accessTechs & ACCESS_TECH_CDMA2000_1XRTT) != 0) { 108 sb.append("CDMA2000_1XRTT|"); 109 } 110 if ((accessTechs & ACCESS_TECH_RESERVED) != 0) { 111 sb.append(String.format("UNKNOWN:%x|", accessTechs & ACCESS_TECH_RESERVED)); 112 } 113 // Trim the tailing pipe character 114 return sb.substring(0, sb.length() - 1); 115 } 116 117 @Override toString()118 public String toString() { 119 return String.format("{PLMN=%s,AccessTechs=%s}", plmn, accessTechString()); 120 } 121 122 /** 123 * Convenience method for extracting all records from encoded bytes 124 */ getRecords(byte[] recordBytes)125 public static PlmnActRecord[] getRecords(byte[] recordBytes) { 126 if (recordBytes == null || recordBytes.length == 0 127 || recordBytes.length % ENCODED_LENGTH != 0) { 128 Rlog.e(LOG_TAG, "Malformed PlmnActRecord, bytes: " 129 + ((recordBytes != null) ? Arrays.toString(recordBytes) : null)); 130 return null; 131 } 132 int numRecords = recordBytes.length / ENCODED_LENGTH; 133 if (VDBG) Rlog.v(LOG_TAG, "Extracting Logs, count=" + numRecords); 134 135 PlmnActRecord[] records = new PlmnActRecord[numRecords]; 136 137 for(int i = 0; i < numRecords; i++) { 138 records[i] = new PlmnActRecord(recordBytes, i * ENCODED_LENGTH); 139 } 140 return records; 141 } 142 143 // Parcelable Implementation 144 @Override describeContents()145 public int describeContents() { 146 return 0; 147 } 148 149 @Override writeToParcel(Parcel dest, int flags)150 public void writeToParcel(Parcel dest, int flags) { 151 dest.writeString(plmn); 152 dest.writeInt(accessTechs); 153 } 154 155 public static final Parcelable.Creator<PlmnActRecord> CREATOR = 156 new Parcelable.Creator<PlmnActRecord>() { 157 @Override 158 public PlmnActRecord createFromParcel(Parcel source) { 159 return new PlmnActRecord(source.readString(), source.readInt()); 160 } 161 162 @Override 163 public PlmnActRecord[] newArray(int size) { 164 return new PlmnActRecord[size]; 165 } 166 }; 167 168 @Override hashCode()169 public int hashCode() { 170 return Objects.hash(plmn, accessTechs); 171 } 172 173 @Override equals(Object rhs)174 public boolean equals(Object rhs) { 175 if (!(rhs instanceof PlmnActRecord)) return false; 176 177 PlmnActRecord r = (PlmnActRecord) rhs; 178 return plmn.equals(r.plmn) && accessTechs == r.accessTechs; 179 } 180 } 181