RegisteredServicesCacheTest.java revision 9e0d81e8439089845b7ddee21676f3f427a34cca
19e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov/* 29e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Copyright (C) 2015 The Android Open Source Project 39e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 49e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Licensed under the Apache License, Version 2.0 (the "License"); 59e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * you may not use this file except in compliance with the License. 69e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * You may obtain a copy of the License at 79e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 89e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * http://www.apache.org/licenses/LICENSE-2.0 99e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Unless required by applicable law or agreed to in writing, software 119e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * distributed under the License is distributed on an "AS IS" BASIS, 129e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * See the License for the specific language governing permissions and 149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * limitations under the License 159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovpackage android.content.pm; 189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.content.Context; 209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.content.res.Resources; 219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.FileUtils; 229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.Parcel; 239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.Parcelable; 249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.UserHandle; 259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.test.AndroidTestCase; 269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.util.AttributeSet; 279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.util.SparseArray; 289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 299e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlPullParser; 309e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlPullParserException; 319e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlSerializer; 329e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.io.File; 349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.io.IOException; 359e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.ArrayList; 369e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Collection; 379e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.HashMap; 389e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.HashSet; 399e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.List; 409e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Map; 419e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Set; 429e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 439e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov/** 449e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Tests for {@link android.content.pm.RegisteredServicesCache} 459e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 469e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovpublic class RegisteredServicesCacheTest extends AndroidTestCase { 479e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 489e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final ResolveInfo r1 = new ResolveInfo(); 499e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final ResolveInfo r2 = new ResolveInfo(); 509e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final TestServiceType t1 = new TestServiceType("t1", "value1"); 519e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final TestServiceType t2 = new TestServiceType("t2", "value2"); 529e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private File mDataDir; 539e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private File mSyncDir; 549e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 559e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected void setUp() throws Exception { 579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov super.setUp(); 589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov File cacheDir = mContext.getCacheDir(); 599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mDataDir = new File(cacheDir, "testServicesCache"); 609e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov FileUtils.deleteContents(mDataDir); 619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mSyncDir = new File(mDataDir, "system/registered_services"); 629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mSyncDir.mkdirs(); 639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesHappyPath() { 669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 689e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getAllServicesSize(0)); 709e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(0)); 719e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml"); 729e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertTrue("File should be created at " + file, file.length() > 0); 739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Make sure all services can be loaded from xml 749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache = new TestServicesCache(mContext, mDataDir); 759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(0)); 769e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 779e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 789e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesReplaceUid() { 799e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 809e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 819e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 829e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.getAllServices(0); 839e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Invalidate cache and clear update query results 849e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.invalidateCache(0); 859e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.clearServicesForQuerying(); 869e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 879e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 889e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServicesCache.SYSTEM_IMAGE_UID)); 899e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache 909e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov .getAllServices(0); 919e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, allServices.size()); 929e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Set<Integer> uids = new HashSet<>(); 939e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) { 949e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov uids.add(srv.uid); 959e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 969e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertTrue("UID must be updated to the new value", 979e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov uids.contains(TestServicesCache.SYSTEM_IMAGE_UID)); 989e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertFalse("UID must be updated to the new value", uids.contains(2)); 999e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1009e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1019e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesServiceRemoved() { 1029e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 1039e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 1049e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 1059e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getAllServicesSize(0)); 1069e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(0)); 1079e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Re-read data from disk and verify services were saved 1089e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache = new TestServicesCache(mContext, mDataDir); 1099e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(0)); 1109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Now register only one service and verify that another one is removed 1119e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 1129e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(1, cache.getAllServicesSize(0)); 1139e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(0)); 1149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesMultiUser() { 1179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 1189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int u0 = 0; 1199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int u1 = 1; 1209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int pid1 = 1; 1219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(u0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov pid1)); 1239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int u1uid = UserHandle.getUid(u1, 0); 1249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.addServiceForQuerying(u1, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 1259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov u1uid)); 1269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getAllServicesSize(u0)); 1279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getPersistentServicesSize(u0)); 1289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getAllServicesSize(u1)); 1299e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getPersistentServicesSize(u1)); 1309e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3)); 1319e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Re-read data from disk and verify services were saved 1329e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache = new TestServicesCache(mContext, mDataDir); 1339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getPersistentServicesSize(u0)); 1349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(u1, cache.getPersistentServicesSize(u1)); 1359e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1369e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1379e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov /** 1389e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing 1399e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 1409e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private static class TestServicesCache extends RegisteredServicesCache<TestServiceType> { 1419e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest"; 1429e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String SERVICE_META_DATA = "RegisteredServicesCacheTest"; 1439e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String ATTRIBUTES_NAME = "test"; 1449e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Represents UID of a system image process 1459e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final int SYSTEM_IMAGE_UID = 20; 1469e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices 1479e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov = new SparseArray<>(); 1489e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1499e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServicesCache(Context context, File dir) { 1509e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, 1519e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov new TestSerializer(), dir); 1529e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1539e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1549e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 1559e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType parseServiceAttributes(Resources res, String packageName, 1569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov AttributeSet attrs) { 1579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return null; 1589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1609e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 1619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected List<ResolveInfo> queryIntentServices(int userId) { 1629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices 1639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>()); 1649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new ArrayList<>(map.keySet()); 1659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov void addServiceForQuerying(int userId, ResolveInfo resolveInfo, 1689e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ServiceInfo<TestServiceType> serviceInfo) { 1699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId); 1709e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (map == null) { 1719e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov map = new HashMap<>(); 1729e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mServices.put(userId, map); 1739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov map.put(resolveInfo, serviceInfo); 1759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1769e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1779e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov void clearServicesForQuerying() { 1789e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mServices.clear(); 1799e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1809e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1819e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int getPersistentServicesSize(int user) { 1829e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return getPersistentServices(user).size(); 1839e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1849e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1859e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int getAllServicesSize(int user) { 1869e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return getAllServices(user).size(); 1879e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1889e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1899e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 1909e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected boolean inSystemImage(int callerUid) { 1919e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return callerUid == SYSTEM_IMAGE_UID; 1929e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1939e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1949e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 1959e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected ServiceInfo<TestServiceType> parseServiceInfo( 1969e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ResolveInfo resolveInfo) throws XmlPullParserException, IOException { 1979e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int size = mServices.size(); 1989e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov for (int i = 0; i < size; i++) { 1999e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i); 2009e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo); 2019e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (serviceInfo != null) { 2029e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return serviceInfo; 2039e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2049e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2059e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov throw new IllegalArgumentException("Unexpected service " + resolveInfo); 2069e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2079e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2089e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2099e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static class TestSerializer implements XmlSerializerAndParser<TestServiceType> { 2109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2119e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException { 2129e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov out.attribute(null, "type", item.type); 2139e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov out.attribute(null, "value", item.value); 2149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType createFromXml(XmlPullParser parser) 2179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov throws IOException, XmlPullParserException { 2189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String type = parser.getAttributeValue(null, "type"); 2199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String value = parser.getAttributeValue(null, "value"); 2209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType(type, value); 2219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static class TestServiceType implements Parcelable { 2259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String type; 2269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String value; 2279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType(String type, String value) { 2299e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this.type = type; 2309e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this.value = value; 2319e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2329e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public boolean equals(Object o) { 2359e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (this == o) { 2369e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return true; 2379e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2389e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (o == null || getClass() != o.getClass()) { 2399e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return false; 2409e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2419e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2429e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServiceType that = (TestServiceType) o; 2439e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2449e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return type.equals(that.type) && value.equals(that.value); 2459e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2469e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2479e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2489e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public int hashCode() { 2499e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return 31 * type.hashCode() + value.hashCode(); 2509e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2519e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2529e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2539e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public String toString() { 2549e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return "TestServiceType{" + 2559e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov "type='" + type + '\'' + 2569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ", value='" + value + '\'' + 2579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov '}'; 2589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2609e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public int describeContents() { 2619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return 0; 2629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void writeToParcel(Parcel dest, int flags) { 2659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov dest.writeString(type); 2669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov dest.writeString(value); 2679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2689e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType(Parcel source) { 2709e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this(source.readString(), source.readString()); 2719e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2729e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() { 2749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType createFromParcel(Parcel source) { 2759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType(source); 2769e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2779e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2789e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType[] newArray(int size) { 2799e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType[size]; 2809e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2819e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov }; 2829e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2839e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov} 284