1718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/* 2718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Copyright (C) 2009 The Android Open Source Project 3718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 4718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Licensed under the Apache License, Version 2.0 (the "License"); 5718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * you may not use this file except in compliance with the License. 6718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * You may obtain a copy of the License at 7718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 8718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * http://www.apache.org/licenses/LICENSE-2.0 9718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 10718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Unless required by applicable law or agreed to in writing, software 11718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * distributed under the License is distributed on an "AS IS" BASIS, 12718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * See the License for the specific language governing permissions and 14718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * limitations under the License. 15718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 16718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 17718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapackage android.content; 18718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 19718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.pm.RegisteredServicesCache; 205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport android.content.pm.XmlSerializerAndParser; 2120cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackbornimport android.content.res.Resources; 22718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.res.TypedArray; 2383b66b2289a103cc6563cc54f9d54632fd64bffbSuprabh Shuklaimport android.text.TextUtils; 2437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasaniimport android.util.ArrayMap; 25718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 2637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasaniimport android.util.SparseArray; 2737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 2837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasaniimport com.android.internal.annotations.GuardedBy; 2937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlPullParser; 315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlSerializer; 325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlPullParserException; 335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.IOException; 3537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasaniimport java.util.ArrayList; 3637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasaniimport java.util.Collection; 37718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 38718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/** 39718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * A cache of services that export the {@link android.content.ISyncAdapter} interface. 40718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @hide 41718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 427a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeypublic class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType> { 43718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String TAG = "Account"; 44718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 45718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String SERVICE_INTERFACE = "android.content.SyncAdapter"; 46718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String SERVICE_META_DATA = "android.content.SyncAdapter"; 47718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String ATTRIBUTES_NAME = "sync-adapter"; 485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private static final MySerializer sSerializer = new MySerializer(); 49718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 5037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani @GuardedBy("mServicesLock") 5137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani private SparseArray<ArrayMap<String,String[]>> mAuthorityToSyncAdapters 5237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani = new SparseArray<>(); 5337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 547a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkey public SyncAdaptersCache(Context context) { 555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, sSerializer); 56718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 57718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 5820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn public SyncAdapterType parseServiceAttributes(Resources res, 5920cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn String packageName, AttributeSet attrs) { 6020cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn TypedArray sa = res.obtainAttributes(attrs, 61718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana com.android.internal.R.styleable.SyncAdapter); 62718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 63718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana final String authority = 64718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana sa.getString(com.android.internal.R.styleable.SyncAdapter_contentAuthority); 65718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana final String accountType = 66718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana sa.getString(com.android.internal.R.styleable.SyncAdapter_accountType); 6783b66b2289a103cc6563cc54f9d54632fd64bffbSuprabh Shukla if (TextUtils.isEmpty(authority) || TextUtils.isEmpty(accountType)) { 68718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 69718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 704a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana final boolean userVisible = 714a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true); 72e0616ffb741b64e3bc7a1e3ad9def3d50eee53fdFred Quintana final boolean supportsUploading = 73e0616ffb741b64e3bc7a1e3ad9def3d50eee53fdFred Quintana sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_supportsUploading, 74e0616ffb741b64e3bc7a1e3ad9def3d50eee53fdFred Quintana true); 750c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana final boolean isAlwaysSyncable = 760c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_isAlwaysSyncable, 770c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana false); 780c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana final boolean allowParallelSyncs = 790c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_allowParallelSyncs, 800c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana false); 81e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana final String settingsActivity = 82e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana sa.getString(com.android.internal.R.styleable 83e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana .SyncAdapter_settingsActivity); 840c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana return new SyncAdapterType(authority, accountType, userVisible, supportsUploading, 855cb2973495084f8ce3433b579e4b4962ed9d7efcSvetoslav Ganov isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName); 86718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 87718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana sa.recycle(); 88718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 89718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 9137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani @Override 9237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani protected void onServicesChangedLocked(int userId) { 9337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani synchronized (mServicesLock) { 9437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId); 9537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani if (adapterMap != null) { 9637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani adapterMap.clear(); 9737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 9837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 9937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 10037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani super.onServicesChangedLocked(userId); 10137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 10237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 10337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani public String[] getSyncAdapterPackagesForAuthority(String authority, int userId) { 10437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani synchronized (mServicesLock) { 10537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId); 10637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani if (adapterMap == null) { 10737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani adapterMap = new ArrayMap<>(); 10837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani mAuthorityToSyncAdapters.put(userId, adapterMap); 10937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 11037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani // If the mapping exists, return it 11137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani if (adapterMap.containsKey(authority)) { 11237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani return adapterMap.get(authority); 11337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 11437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani // Create the mapping and cache it 11537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani String[] syncAdapterPackages; 11637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos; 11737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani serviceInfos = getAllServices(userId); 11837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani ArrayList<String> packages = new ArrayList<>(); 11937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) { 12037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani if (authority.equals(serviceInfo.type.authority) 12137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani && serviceInfo.componentName != null) { 12237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani packages.add(serviceInfo.componentName.getPackageName()); 12337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 12437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 12537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani syncAdapterPackages = new String[packages.size()]; 12637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani packages.toArray(syncAdapterPackages); 12737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani adapterMap.put(authority, syncAdapterPackages); 12837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 12937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani return syncAdapterPackages; 13037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 13137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 13237a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 13337a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani @Override 13437a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani protected void onUserRemoved(int userId) { 13537a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani synchronized (mServicesLock) { 13637a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani mAuthorityToSyncAdapters.remove(userId); 13737a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 13837a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 13937a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani super.onUserRemoved(userId); 14037a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani } 14137a40c24deb02bca3868a8085069afae112f22e4Amith Yamasani 1425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana static class MySerializer implements XmlSerializerAndParser<SyncAdapterType> { 1435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException { 1445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.attribute(null, "authority", item.authority); 1455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.attribute(null, "accountType", item.accountType); 1465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1470c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana 1485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public SyncAdapterType createFromXml(XmlPullParser parser) 1495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana throws IOException, XmlPullParserException { 1505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final String authority = parser.getAttributeValue(null, "authority"); 1515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final String accountType = parser.getAttributeValue(null, "accountType"); 1525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return SyncAdapterType.newKey(authority, accountType); 1535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1550c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana} 156