1971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey/* 2971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project 3971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * 4971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * you may not use this file except in compliance with the License. 6971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * You may obtain a copy of the License at 7971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * 8971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * 10971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 11971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * See the License for the specific language governing permissions and 14971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * limitations under the License. 15971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey */ 16971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 17971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkeypackage com.android.internal.net; 18971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 1982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.os.Parcel; 2082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.os.Parcelable; 2169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.text.TextUtils; 2269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport android.util.Log; 2382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 2469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkeyimport java.net.InetAddress; 25971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkeyimport java.nio.charset.Charsets; 26971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 27971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey/** 28971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * Parcel-like entity class for VPN profiles. To keep things simple, all 29971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * fields are package private. Methods are provided for serialization, so 30971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * storage can be implemented easily. Two rules are set for this class. 31971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * First, all fields must be kept non-null. Second, always make a copy 32971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * using clone() before modifying. 33971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * 34971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey * @hide 35971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey */ 3682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeypublic class VpnProfile implements Cloneable, Parcelable { 3769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey private static final String TAG = "VpnProfile"; 3869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 39971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey // Match these constants with R.array.vpn_types. 40971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_PPTP = 0; 41971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_L2TP_IPSEC_PSK = 1; 42971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_L2TP_IPSEC_RSA = 2; 43971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_IPSEC_XAUTH_PSK = 3; 44971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_IPSEC_XAUTH_RSA = 4; 45971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_IPSEC_HYBRID_RSA = 5; 46971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static final int TYPE_MAX = 5; 47971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 48971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey // Entity fields. 49971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public final String key; // -1 50971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String name = ""; // 0 51971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public int type = TYPE_PPTP; // 1 52971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String server = ""; // 2 53971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String username = ""; // 3 54971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String password = ""; // 4 55971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String dnsServers = ""; // 5 56971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String searchDomains = ""; // 6 57971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String routes = ""; // 7 58971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public boolean mppe = true; // 8 59971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String l2tpSecret = ""; // 9 60971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String ipsecIdentifier = "";// 10 61971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String ipsecSecret = ""; // 11 62971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String ipsecUserCert = ""; // 12 63971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String ipsecCaCert = ""; // 13 64971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public String ipsecServerCert = "";// 14 65971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 66971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey // Helper fields. 67971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public boolean saveLogin = false; 68971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 69971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public VpnProfile(String key) { 70971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey this.key = key; 71971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 72971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 736e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey public VpnProfile(Parcel in) { 746e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey key = in.readString(); 756e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey name = in.readString(); 766e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey type = in.readInt(); 776e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey server = in.readString(); 786e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey username = in.readString(); 796e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey password = in.readString(); 806e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey dnsServers = in.readString(); 816e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey searchDomains = in.readString(); 826e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey routes = in.readString(); 836e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey mppe = in.readInt() != 0; 846e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey l2tpSecret = in.readString(); 856e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey ipsecIdentifier = in.readString(); 866e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey ipsecSecret = in.readString(); 876e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey ipsecUserCert = in.readString(); 886e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey ipsecCaCert = in.readString(); 896e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey ipsecServerCert = in.readString(); 906e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey saveLogin = in.readInt() != 0; 916e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey } 926e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey 936e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey @Override 946e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey public void writeToParcel(Parcel out, int flags) { 956e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(key); 966e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(name); 976e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeInt(type); 986e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(server); 996e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(username); 1006e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(password); 1016e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(dnsServers); 1026e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(searchDomains); 1036e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(routes); 1046e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeInt(mppe ? 1 : 0); 1056e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(l2tpSecret); 1066e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(ipsecIdentifier); 1076e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(ipsecSecret); 1086e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(ipsecUserCert); 1096e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(ipsecCaCert); 1106e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeString(ipsecServerCert); 1116e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey out.writeInt(saveLogin ? 1 : 0); 1126e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey } 1136e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey 114971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public static VpnProfile decode(String key, byte[] value) { 115971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey try { 116971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey if (key == null) { 117971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return null; 118971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 119971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 120971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey String[] values = new String(value, Charsets.UTF_8).split("\0", -1); 121971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey // There can be 14 or 15 values in ICS MR1. 122971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey if (values.length < 14 || values.length > 15) { 123971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return null; 124971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 125971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 126971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey VpnProfile profile = new VpnProfile(key); 127971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.name = values[0]; 128971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.type = Integer.valueOf(values[1]); 129971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey if (profile.type < 0 || profile.type > TYPE_MAX) { 130971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return null; 131971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 132971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.server = values[2]; 133971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.username = values[3]; 134971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.password = values[4]; 135971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.dnsServers = values[5]; 136971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.searchDomains = values[6]; 137971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.routes = values[7]; 138971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.mppe = Boolean.valueOf(values[8]); 139971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.l2tpSecret = values[9]; 140971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.ipsecIdentifier = values[10]; 141971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.ipsecSecret = values[11]; 142971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.ipsecUserCert = values[12]; 143971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.ipsecCaCert = values[13]; 144971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.ipsecServerCert = (values.length > 14) ? values[14] : ""; 145971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 146971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty(); 147971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return profile; 148971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } catch (Exception e) { 149971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey // ignore 150971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 151971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return null; 152971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 153971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey 154971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey public byte[] encode() { 155971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey StringBuilder builder = new StringBuilder(name); 156971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(type); 157971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(server); 158971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(saveLogin ? username : ""); 159971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(saveLogin ? password : ""); 160971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(dnsServers); 161971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(searchDomains); 162971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(routes); 163971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(mppe); 164971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(l2tpSecret); 165971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(ipsecIdentifier); 166971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(ipsecSecret); 167971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(ipsecUserCert); 168971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(ipsecCaCert); 169971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey builder.append('\0').append(ipsecServerCert); 170971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey return builder.toString().getBytes(Charsets.UTF_8); 171971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey } 17282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 17369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey /** 17469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * Test if profile is valid for lockdown, which requires IPv4 address for 17569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * both server and DNS. Server hostnames would require using DNS before 17669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey * connection. 17769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey */ 17869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public boolean isValidLockdownProfile() { 17969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey try { 18069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey InetAddress.parseNumericAddress(server); 18169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 18269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey for (String dnsServer : dnsServers.split(" +")) { 18369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey InetAddress.parseNumericAddress(this.dnsServers); 18469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 18569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (TextUtils.isEmpty(dnsServers)) { 18669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey Log.w(TAG, "DNS required"); 18769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return false; 18869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 18969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 19069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey // Everything checked out above 19169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return true; 19269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 19369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } catch (IllegalArgumentException e) { 19469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey Log.w(TAG, "Invalid address", e); 19569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return false; 19669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 19769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 19869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 19982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() { 20082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey @Override 20182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public VpnProfile createFromParcel(Parcel in) { 2026e7aa77565553e487a1e14478d9c30f512156232Jeff Sharkey return new VpnProfile(in); 20382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 20482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 20582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey @Override 20682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public VpnProfile[] newArray(int size) { 20782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey return new VpnProfile[size]; 20882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 20982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 21082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 21182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey @Override 21282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public int describeContents() { 21382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey return 0; 21482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 215971a3cfa51b89aa0f3ab47ee082f05586a1f16f0Jeff Sharkey} 216