public void setSyncActivated(boolean enabled) { ContentResolver.setMasterSyncAutomatically(enabled); if (enabled) { SyncAdapterType[] types = ContentResolver.getSyncAdapterTypes(); AccountManager accmgr = AccountManager.get(mContext); for (SyncAdapterType type : types) { Account[] accounts = accmgr.getAccountsByType(type.accountType); for (Account account : accounts) { if (Constants.DEBUG) { Log.d(TAG, "synching account, name:" + account.name + ", type: " + account.type); } enabled = ContentResolver.getSyncAutomatically(account, type.authority); if (enabled) { // trigger update for next account ContentResolver.requestSync(account, type.authority, new Bundle()); } } } } }
private void generateServicesMap(List<ResolveInfo> services, Map<String, SyncAdapterInfo> map, RegisteredServicesParser accountParser) { for (ResolveInfo info : services) { XmlResourceParser parser = accountParser.getParser(mContext, info.serviceInfo, "android.content.SyncAdapter"); if (parser != null) { try { AttributeSet attributeSet = Xml.asAttributeSet(parser); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { // Nothing to do } if ("sync-adapter".equals(parser.getName())) { SyncAdapterType adapterType = parseSyncAdapterType( accountParser.getResources(mContext, info.serviceInfo.applicationInfo), attributeSet); if (adapterType != null) { String key = adapterType.accountType + "/" + adapterType.authority; map.put(key, new SyncAdapterInfo(adapterType, info.serviceInfo)); } } } catch (Exception e) { e.printStackTrace(); } } } }
/** * Enables syncing of a SyncAdapter for a given content provider. * * <p>Adds the authority to a whitelist, and immediately requests a sync. * * @param username Username of the account (including @gmail.com). * @param authority The authority of a content provider that should be synced. */ @Rpc(description = "Enables syncing of a SyncAdapter for a content provider.") public void startSync(String username, String authority) throws AccountSnippetException { if (!listAccounts().contains(username)) { throw new AccountSnippetException("Account " + username + " is not on the device"); } // Add to the whitelist mLock.writeLock().lock(); try { if (mSyncWhitelist.containsKey(username)) { mSyncWhitelist.get(username).add(authority); } else { mSyncWhitelist.put(username, new HashSet<String>(Arrays.asList(authority))); } // Update the Sync settings for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) { // Find the Google account content provider. if (adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE) && adapter.authority.equals(authority)) { Account account = new Account(username, GOOGLE_ACCOUNT_TYPE); updateSync(account, authority, true); } } } finally { mLock.writeLock().unlock(); } }
/** * Disables syncing of a SyncAdapter for a given content provider. * * <p>Removes the content provider authority from a whitelist. * * @param username Username of the account (including @gmail.com). * @param authority The authority of a content provider that should not be synced. */ @Rpc(description = "Disables syncing of a SyncAdapter for a content provider.") public void stopSync(String username, String authority) throws AccountSnippetException { if (!listAccounts().contains(username)) { throw new AccountSnippetException("Account " + username + " is not on the device"); } // Remove from whitelist mLock.writeLock().lock(); try { if (mSyncWhitelist.containsKey(username)) { Set<String> whitelistedProviders = mSyncWhitelist.get(username); whitelistedProviders.remove(authority); if (whitelistedProviders.isEmpty()) { mSyncWhitelist.remove(username); } } // Update the Sync settings for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) { // Find the Google account content provider. if (adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE) && adapter.authority.equals(authority)) { Account account = new Account(username, GOOGLE_ACCOUNT_TYPE); updateSync(account, authority, false); } } } finally { mLock.writeLock().unlock(); } }
private SyncAdapterType parseSyncAdapterType(Resources res, AttributeSet set) { TypedArray obtainAttributes = res.obtainAttributes(set, R_Hide.styleable.SyncAdapter.get()); try { String contentAuthority = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_contentAuthority.get()); String accountType = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_accountType.get()); if (contentAuthority == null || accountType == null) { obtainAttributes.recycle(); return null; } boolean userVisible = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_userVisible.get(), true); boolean supportsUploading = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_supportsUploading.get(), true); boolean isAlwaysSyncable = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_isAlwaysSyncable.get(), true); boolean allowParallelSyncs = obtainAttributes.getBoolean(R_Hide.styleable.SyncAdapter_allowParallelSyncs.get(), true); String settingsActivity = obtainAttributes.getString(R_Hide.styleable.SyncAdapter_settingsActivity.get()); SyncAdapterType type; if (SyncAdapterTypeN.ctor != null) { type = SyncAdapterTypeN.ctor.newInstance(contentAuthority, accountType, userVisible, supportsUploading, isAlwaysSyncable, allowParallelSyncs, settingsActivity, null); obtainAttributes.recycle(); return type; } type = mirror.android.content.SyncAdapterType.ctor.newInstance(contentAuthority, accountType, userVisible, supportsUploading, isAlwaysSyncable, allowParallelSyncs, settingsActivity); obtainAttributes.recycle(); return type; } catch (Throwable e) { e.printStackTrace(); } return null; }
public static ArrayList<String> getAuthorities() { SyncAdapterType[] syncAdapterTypes = ContentResolver.getSyncAdapterTypes(); ArrayList<String> syncAuthorities = new ArrayList<>(); for (SyncAdapterType type: syncAdapterTypes) { if (DEBUG) Log.d(LOG_TAG, "Found sync type " + type); if (!syncAuthorities.contains(type.authority)) { syncAuthorities.add(type.authority); if (DEBUG) Log.d(LOG_TAG, "Added sync authority " + type.authority); } } return syncAuthorities; }
/** * Adds a Google account to the device. * * <p>TODO(adorokhine): Support adding accounts of other types with an optional 'type' kwarg. * * <p>TODO(adorokhine): Allow users to choose whether to enable/disable sync with a kwarg. * * @param username Username of the account to add (including @gmail.com). * @param password Password of the account to add. */ @Rpc( description = "Add a Google (GMail) account to the device, with account data sync disabled." ) public void addAccount(String username, String password) throws AccountSnippetException, AccountsException, IOException { // Check for existing account. If we try to re-add an existing account, Android throws an // exception that says "Account does not exist or not visible. Maybe change pwd?" which is // a little hard to understand. if (listAccounts().contains(username)) { throw new AccountSnippetException( "Account " + username + " already exists on the device"); } Bundle addAccountOptions = new Bundle(); addAccountOptions.putString("username", username); addAccountOptions.putString("password", password); AccountManagerFuture<Bundle> future = mAccountManager.addAccount( GOOGLE_ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null /* requiredFeatures */, addAccountOptions, null /* activity */, null /* authCallback */, null /* handler */); Bundle result = future.getResult(); if (result.containsKey(AccountManager.KEY_ERROR_CODE)) { throw new AccountSnippetException( String.format( Locale.US, "Failed to add account due to code %d: %s", result.getInt(AccountManager.KEY_ERROR_CODE), result.getString(AccountManager.KEY_ERROR_MESSAGE))); } // Disable sync to avoid test flakiness as accounts fetch additional data. // It takes a while for all sync adapters to be populated, so register for broadcasts when // sync is starting and disable them there. // NOTE: this listener is NOT unregistered because several sync requests for the new account // will come in over time. Account account = new Account(username, GOOGLE_ACCOUNT_TYPE); Object handle = ContentResolver.addStatusChangeListener( ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE | ContentResolver.SYNC_OBSERVER_TYPE_PENDING, which -> { for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) { // Ignore non-Google account types. if (!adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE)) { continue; } // If a content provider is not whitelisted, then disable it. // Because startSync and stopSync synchronously update the whitelist // and sync settings, writelock both the whitelist check and the // call to sync together. mLock.writeLock().lock(); try { if (!isAdapterWhitelisted(username, adapter.authority)) { updateSync(account, adapter.authority, false /* sync */); } } finally { mLock.writeLock().unlock(); } } }); mSyncStatusObserverHandles.add(handle); }
SyncAdapterInfo(SyncAdapterType adapterType, ServiceInfo serviceInfo) { this.adapterType = adapterType; this.serviceInfo = serviceInfo; }
@Override protected void after(XParam param) throws Throwable { switch (mMethod) { case getCurrentSync: if (isRestricted(param)) param.setResult(null); break; case getCurrentSyncs: if (isRestricted(param)) param.setResult(new ArrayList<SyncInfo>()); break; case getSyncAdapterTypes: if (isRestricted(param)) param.setResult(new SyncAdapterType[0]); break; case openAssetFileDescriptor: case openFileDescriptor: case openInputStream: case openOutputStream: case openTypedAssetFileDescriptor: case openAssetFile: case openFile: if (param.args.length > 0 && param.args[0] instanceof Uri) { String uri = ((Uri) param.args[0]).toString(); if (isRestrictedExtra(param, uri)) param.setThrowable(new FileNotFoundException("XPrivacy")); } break; case Srv_call: handleCallAfter(param); break; case query: case Srv_query: handleUriAfter(param); break; case Srv_getCurrentSyncs: case Srv_getCurrentSyncsAsUser: if (param.getResult() != null) if (isRestricted(param)) { int uid = Binder.getCallingUid(); @SuppressWarnings("unchecked") List<SyncInfo> listSync = (List<SyncInfo>) param.getResult(); List<SyncInfo> listFiltered = new ArrayList<SyncInfo>(); for (SyncInfo sync : listSync) if (XAccountManager.isAccountAllowed(sync.account, uid)) listFiltered.add(sync); param.setResult(listFiltered); } break; } }
@Override protected void after(XParam param) throws Throwable { switch (mMethod) { case getCurrentSync: if (isRestricted(param)) param.setResult(null); break; case getCurrentSyncs: if (isRestricted(param)) param.setResult(new ArrayList<SyncInfo>()); break; case getSyncAdapterTypes: if (isRestricted(param)) param.setResult(new SyncAdapterType[0]); break; case openAssetFileDescriptor: case openFileDescriptor: case openInputStream: case openOutputStream: case openTypedAssetFileDescriptor: case openAssetFile: case openFile: if (param.args.length > 0 && param.args[0] instanceof Uri) { String uri = ((Uri) param.args[0]).toString(); switch(getRestrictStateExtra(param, uri)){ case 0: //Log.d("Smarper-Storage", "XContentResolver, " + mMethod + ": " + uri + " allowed"); break; case 1: if (!SmarperUtil.forbiddenPathsInitialized) SmarperUtil.initializeForbiddenPaths(); if (uri.startsWith(SmarperUtil.moviesURI.toString()) || uri.startsWith(SmarperUtil.dcimURI.toString()) || uri.startsWith(SmarperUtil.picturesURI.toString()) || uri.startsWith(SmarperUtil.musicURI.toString())){ param.setThrowable(new FileNotFoundException("XPrivacy")); //Log.d("Smarper-Storage", "XContentResolver, " + mMethod + ": Obfuscating " + uri); } else{ // //Log.d("Smarper-Storage", "ContentResolver: " + uri + " not in public folders list, not obfuscated!"); } break; case 2: param.setThrowable(new FileNotFoundException("XPrivacy")); break; } } break; case Srv_call: handleCallAfter(param); break; case query: case Srv_query: handleUriAfter(param); break; case Srv_getCurrentSyncs: case Srv_getCurrentSyncsAsUser: if (param.getResult() != null) if (isRestricted(param)) { int uid = Binder.getCallingUid(); @SuppressWarnings("unchecked") List<SyncInfo> listSync = (List<SyncInfo>) param.getResult(); List<SyncInfo> listFiltered = new ArrayList<SyncInfo>(); for (SyncInfo sync : listSync) if (XAccountManager.isAccountAllowed(sync.account, uid)) listFiltered.add(sync); param.setResult(listFiltered); } break; } }
@Override protected void requestStateChange(final Context context, boolean desiredState) { if (!desiredState) { return; } final boolean syncAll = !Globals.getAppPrefs(context).getBoolean("sync_now_idp", false); updater = new UiUpdater(context); syncTask = new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { Account[] allAccounts = AccountManager.get(context).getAccounts(); SyncAdapterType[] types = ContentResolver.getSyncAdapterTypes(); for (Account account : allAccounts) { for (SyncAdapterType type : types) { if (account.type.equals(type.accountType)) { boolean doSync = (ContentResolver.getIsSyncable(account, type.authority) > 0) && (syncAll || ContentResolver.getSyncAutomatically(account, type.authority)); if (doSync) { Bundle bundle = new Bundle(); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); ContentResolver.requestSync(account, type.authority, bundle); } } } } return null; } @Override protected void onPostExecute(Void result) { syncTask = null; infoToast = Toast.makeText(context, syncAll ? R.string.msg_account_synced : R.string.msg_e_account_synced, Toast.LENGTH_LONG); infoToast.show(); updater.refresh(); if (!updater.handler.postDelayed(SyncNowTracker.this, 3000)) { run(); } } }.execute(); }
@Override public void onAccountsUpdated(Account[] a) { MyLog.i(TAG, "Account list update detected"); // Clear out any old data to prevent duplicates mAccounts.clear(); // Get account data from system AuthenticatorDescription[] accountTypes = AccountManager.get(this).getAuthenticatorTypes(); // Also, get a list of all sync adapters and find the ones that // support contacts: SyncAdapterType[] syncs = ContentResolver.getSyncAdapterTypes(); ArrayList<String> contactAccountTypes = new ArrayList<String>(); for (SyncAdapterType sync : syncs) { if (ContactsContract.AUTHORITY.equals(sync.authority) && sync.supportsUploading()) { contactAccountTypes.add(sync.accountType); } } // Populate tables for (int i = 0; i < a.length; i++) { // The user may have multiple accounts with the same name, so we // need to construct a // meaningful display name for each. String systemAccountType = a[i].type; AuthenticatorDescription ad = getAuthenticatorDescription(systemAccountType, accountTypes); if (ad != null) { AccountData data = new AccountData(this, a[i].name, ad); // filter on accounts that support contacts if (contactAccountTypes.contains(a[i].type)) mAccounts.add(data); } } // unsync account AuthenticatorDescription adNull = new AuthenticatorDescription(mUnsyncType, UNSYNC_PKG, 0, 0, 0, 0); AccountData aNull = new AccountData(this, mUnsyncName, adNull); mAccounts.add(aNull); // Update the account spinner mAccountAdapter.notifyDataSetChanged(); }