Add handling for account tiles for specific account type.

- List individual account instead of account type under User & account
  screen.

- Add handling to move account tiles with specific account type from
  top level account dashboard to inside the corresponding account
  preference.

- Rename settings.accounts.AccountPreference to
  settings.accounts.AccountTypePreference to make it less confused
  with settings.AccountPreference

Bug: 31801423
Test: make RunSettingsRoboTests
Change-Id: Iebe70a3c4230e8d979344f142a5c2a60945e552e
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9aa7608..57ae326 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7975,6 +7975,8 @@
     <string name="auto_sync_personal_account_title">Auto sync personal account data</string>
     <!-- Switch label to enable auto sync work account [CHAR LIMIT=60] -->
     <string name="auto_sync_work_account_title">Auto sync work account data</string>
+    <!-- Preference label to sync account [CHAR LIMIT=60] -->
+    <string name="account_sync_title">Account sync</string>
 
     <!-- Enterprise Privacy --> <skip />
 
diff --git a/res/xml/account_type_settings.xml b/res/xml/account_type_settings.xml
new file mode 100644
index 0000000..f9e5aa8
--- /dev/null
+++ b/res/xml/account_type_settings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+        android:title="@string/account_settings_title"
+        settings:keywords="@string/keywords_accounts">
+
+    <Preference
+        android:key="account_sync"
+        android:title="@string/account_sync_title"
+        android:order="1"/>
+
+    <PreferenceCategory
+      android:key="dashboard_tile_placeholder"
+      android:order="10"/>
+
+</PreferenceScreen>
diff --git a/res/xml/user_and_accounts_settings.xml b/res/xml/user_and_accounts_settings.xml
index 1c487ae..73b574f 100644
--- a/res/xml/user_and_accounts_settings.xml
+++ b/res/xml/user_and_accounts_settings.xml
@@ -52,4 +52,8 @@
         settings:useAdditionalSummary="true"
         android:order="105"/>
 
+    <PreferenceCategory
+      android:key="dashboard_tile_placeholder"
+      android:order="200"/>
+
 </PreferenceScreen>
diff --git a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
new file mode 100644
index 0000000..cf0a0a8
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.accounts;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.Tile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AccountDetailDashboardFragment extends DashboardFragment {
+
+    private static final String TAG = "AccountDetailDashboard";
+    private static final String METADATA_IA_ACCOUNT = "com.android.settings.ia.account";
+
+    public static final String KEY_ACCOUNT = "account";
+    public static final String KEY_ACCOUNT_TYPE = "account_type";
+    public static final String KEY_ACCOUNT_LABEL = "account_label";
+    public static final String KEY_ACCOUNT_TITLE_RES = "account_title_res";
+
+    private String mAccountLabel;
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    String mAccountType;
+    private AccountSyncPreferenceController mAccountSynController;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Bundle args = getArguments();
+        final Activity activity = getActivity();
+        UserHandle userHandle = Utils.getSecureTargetUser(activity.getActivityToken(),
+            (UserManager) getSystemService(Context.USER_SERVICE), args,
+            activity.getIntent().getExtras());
+        Account account = null;
+        if (args != null) {
+            if (args.containsKey(KEY_ACCOUNT)) {
+                account = args.getParcelable(KEY_ACCOUNT);
+            }
+            if (args.containsKey(KEY_ACCOUNT_LABEL)) {
+                mAccountLabel = args.getString(KEY_ACCOUNT_LABEL);
+            }
+            if (args.containsKey(KEY_ACCOUNT_TYPE)) {
+                mAccountType = args.getString(KEY_ACCOUNT_TYPE);
+            }
+        }
+        mAccountSynController.init(account, userHandle);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        if (mAccountLabel != null) {
+            getActivity().setTitle(mAccountLabel);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.ACCOUNT;
+    }
+
+    @Override
+    protected String getCategoryKey() {
+        return CategoryKey.CATEGORY_ACCOUNT;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.account_type_settings;
+    }
+
+    @Override
+    protected List<PreferenceController> getPreferenceControllers(Context context) {
+        final List<PreferenceController> controllers = new ArrayList<>();
+        mAccountSynController = new AccountSyncPreferenceController(context);
+        controllers.add(mAccountSynController);
+        return controllers;
+    }
+
+    @Override
+    protected boolean displayTile(Tile tile) {
+        if (mAccountType == null) {
+            return false;
+        }
+        final Bundle metadata = tile.metaData;
+        if (metadata == null) {
+            return false;
+        }
+        return mAccountType.equals(metadata.getString(METADATA_IA_ACCOUNT));
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index fa99f77..2a8eaf6 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -47,6 +48,7 @@
 import com.android.settings.core.lifecycle.LifecycleObserver;
 import com.android.settings.core.lifecycle.events.OnPause;
 import com.android.settings.core.lifecycle.events.OnResume;
+import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.Index;
 import com.android.settings.search.SearchIndexableRaw;
@@ -86,6 +88,7 @@
     private boolean mIAEnabled;
     private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
     private AccountRestrictionHelper mHelper;
+    private DashboardFeatureProvider mDashboardFeatureProvider;
 
     /**
      * Holds data related to the accounts belonging to one profile.
@@ -132,8 +135,9 @@
         if (mAuthorities != null) {
             mAuthoritiesCount = mAuthorities.length;
         }
-        mIAEnabled = FeatureFactory.getFactory(mContext).getDashboardFeatureProvider(mContext)
-            .isEnabled();
+        mDashboardFeatureProvider =
+            FeatureFactory.getFactory(mContext).getDashboardFeatureProvider(mContext);
+        mIAEnabled = mDashboardFeatureProvider.isEnabled();
         mHelper = helper;
     }
 
@@ -250,11 +254,6 @@
     }
 
     private void updateUi() {
-        if (!mIAEnabled) {
-            // Load the preferences from an XML resource
-            mParent.addPreferencesFromResource(R.xml.account_settings);
-        }
-
         if (!isAvailable()) {
             // This should not happen
             Log.e(TAG, "We should not be showing settings for a managed profile");
@@ -264,6 +263,11 @@
             return;
         }
 
+        if (!mIAEnabled) {
+            // Load the preferences from an XML resource
+            mParent.addPreferencesFromResource(R.xml.account_settings);
+        }
+
         if (mUm.isLinkedUser()) {
             // Restricted user or similar
             UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
@@ -400,7 +404,7 @@
     private void updateAccountTypes(ProfileData profileData) {
         profileData.preferenceGroup.removeAll();
         if (profileData.userInfo.isEnabled()) {
-            final ArrayList<AccountPreference> preferences = getAccountTypePreferences(
+            final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
                     profileData.authenticatorHelper, profileData.userInfo.getUserHandle());
             final int count = preferences.size();
             for (int i = 0; i < count; i++) {
@@ -430,11 +434,11 @@
         }
     }
 
-    private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper,
+    private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
             UserHandle userHandle) {
         final String[] accountTypes = helper.getEnabledAccountTypes();
-        final ArrayList<AccountPreference> accountTypePreferences =
-                new ArrayList<AccountPreference>(accountTypes.length);
+        final ArrayList<AccountTypePreference> accountTypePreferences =
+                new ArrayList<AccountTypePreference>(accountTypes.length);
 
         for (int i = 0; i < accountTypes.length; i++) {
             final String accountType = accountTypes[i];
@@ -453,17 +457,40 @@
                     .getAccountsByTypeAsUser(accountType, userHandle);
             final boolean skipToAccount = accounts.length == 1
                     && !helper.hasAccountPreferences(accountType);
+            final Drawable icon = helper.getDrawableForType(mContext, accountType);
+            final Context prefContext = mParent.getPreferenceManager().getContext();
 
-            if (skipToAccount) {
+            if (mIAEnabled) {
+                // Add a preference row for each individual account
+                for (Account account : accounts) {
+                    final ArrayList<String> auths =
+                        helper.getAuthoritiesForAccountType(account.type);
+                    if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
+                        continue;
+                    }
+                    final Bundle fragmentArguments = new Bundle();
+                    fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
+                        account);
+                    fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
+                        accountType);
+                    fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
+                        label.toString());
+                    fragmentArguments.putInt(AccountDetailDashboardFragment.KEY_ACCOUNT_TITLE_RES,
+                        titleResId);
+                    fragmentArguments.putParcelable(EXTRA_USER, userHandle);
+                    accountTypePreferences.add(new AccountTypePreference(
+                        prefContext, account.name, titleResPackageName, titleResId, label,
+                        AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
+                }
+            } else if (skipToAccount) {
                 final Bundle fragmentArguments = new Bundle();
                 fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
                         accounts[0]);
                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
 
-                accountTypePreferences.add(new AccountPreference(
-                    mParent.getPreferenceManager().getContext(), label, titleResPackageName,
-                    titleResId, AccountSyncSettings.class.getName(), fragmentArguments,
-                    helper.getDrawableForType(mContext, accountType)));
+                accountTypePreferences.add(new AccountTypePreference(
+                        prefContext, label, titleResPackageName,
+                    titleResId, AccountSyncSettings.class.getName(), fragmentArguments, icon));
             } else {
                 final Bundle fragmentArguments = new Bundle();
                 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
@@ -471,18 +498,23 @@
                         label.toString());
                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
 
-                accountTypePreferences.add(new AccountPreference(
-                    mParent.getPreferenceManager().getContext(), label, titleResPackageName,
-                    titleResId, ManageAccountsSettings.class.getName(), fragmentArguments,
-                    helper.getDrawableForType(mContext, accountType)));
+                accountTypePreferences.add(new AccountTypePreference(
+
+                        prefContext, label, titleResPackageName,
+                    titleResId, ManageAccountsSettings.class.getName(), fragmentArguments, icon));
             }
             helper.preloadDrawableForType(mContext, accountType);
         }
         // Sort by label
-        Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() {
+        Collections.sort(accountTypePreferences, new Comparator<AccountTypePreference>() {
             @Override
-            public int compare(AccountPreference t1, AccountPreference t2) {
-                return t1.getitle().toString().compareTo(t2.getitle().toString());
+            public int compare(AccountTypePreference t1, AccountTypePreference t2) {
+                int result = 0;
+                if (mIAEnabled) {
+                    result = t1.getSummary().toString().compareTo(t2.getSummary().toString());
+                }
+                return result != 0
+                    ? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
             }
         });
         return accountTypePreferences;
diff --git a/src/com/android/settings/accounts/AccountRestrictionHelper.java b/src/com/android/settings/accounts/AccountRestrictionHelper.java
index 868fa1c..43c56ba 100644
--- a/src/com/android/settings/accounts/AccountRestrictionHelper.java
+++ b/src/com/android/settings/accounts/AccountRestrictionHelper.java
@@ -20,6 +20,7 @@
 import com.android.settings.AccessiblePreferenceCategory;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
+import java.util.ArrayList;
 
 public class AccountRestrictionHelper {
 
@@ -55,4 +56,22 @@
         return new AccessiblePreferenceCategory(context);
     }
 
+    /**
+     * Checks if the account should be shown based on the required authorities for the account type
+     * @param authorities given authority that is passed as activity extra
+     * @param auths list of authorities for particular account type
+     * @return true if the activity has the required authority to show the account
+     */
+    public static boolean showAccount(String[] authorities, ArrayList<String> auths) {
+        boolean showAccount = true;
+        if (authorities != null && auths != null) {
+            showAccount = false;
+            for (String requestedAuthority : authorities) {
+                if (auths.contains(requestedAuthority)) {
+                    return true;
+                }
+            }
+        }
+        return showAccount;
+    }
 }
diff --git a/src/com/android/settings/accounts/AccountSyncPreferenceController.java b/src/com/android/settings/accounts/AccountSyncPreferenceController.java
new file mode 100644
index 0000000..76750b3
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountSyncPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accounts;
+
+import static android.content.Intent.EXTRA_USER;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+
+public class AccountSyncPreferenceController extends PreferenceController {
+
+    private static final String TAG = "AccountSyncController";
+    private static final String KEY_ACCOUNT_SYNC = "account_sync";
+
+    private Account mAccount;
+    private UserHandle mUserHandle;
+
+    public AccountSyncPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!KEY_ACCOUNT_SYNC.equals(preference.getKey())) {
+            return false;
+        }
+        final Bundle args = new Bundle();
+        args.putParcelable(AccountSyncSettings.ACCOUNT_KEY, mAccount);
+        args.putParcelable(EXTRA_USER, mUserHandle);
+        Utils.startWithFragment(mContext, AccountSyncSettings.class.getName(), args, null, 0, -1,
+            mAccount.name);
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ACCOUNT_SYNC;
+    }
+
+    public void init(Account account, UserHandle userHandle) {
+        mAccount = account;
+        mUserHandle = userHandle;
+    }
+}
diff --git a/src/com/android/settings/accounts/AccountPreference.java b/src/com/android/settings/accounts/AccountTypePreference.java
similarity index 80%
rename from src/com/android/settings/accounts/AccountPreference.java
rename to src/com/android/settings/accounts/AccountTypePreference.java
index 38cb437..bf3b9f5 100644
--- a/src/com/android/settings/accounts/AccountPreference.java
+++ b/src/com/android/settings/accounts/AccountTypePreference.java
@@ -29,7 +29,7 @@
 
 import static android.content.Intent.EXTRA_USER;
 
-public class AccountPreference extends Preference implements OnPreferenceClickListener {
+public class AccountTypePreference extends Preference implements OnPreferenceClickListener {
     /**
      * Title of the tile that is shown to the user.
      * @attr ref android.R.styleable#PreferenceHeader_title
@@ -48,6 +48,11 @@
     private final int mTitleResId;
 
     /**
+     * Summary of the tile that is shown to the user.
+     */
+    private final CharSequence mSummary;
+
+    /**
      * Full class name of the fragment to display when this tile is
      * selected.
      * @attr ref android.R.styleable#PreferenceHeader_fragment
@@ -60,17 +65,26 @@
      */
     private final Bundle mFragmentArguments;
 
-    public AccountPreference(Context context, CharSequence title, String titleResPackageName,
+    public AccountTypePreference(Context context, CharSequence title, String titleResPackageName,
         int titleResId, String fragment, Bundle fragmentArguments, Drawable icon) {
+        this(context, title, titleResPackageName, titleResId, null, fragment, fragmentArguments,
+            icon);
+    }
+
+    public AccountTypePreference(Context context, CharSequence title, String titleResPackageName,
+        int titleResId, CharSequence summary, String fragment, Bundle fragmentArguments,
+        Drawable icon) {
         super(context);
         mTitle = title;
         mTitleResPackageName = titleResPackageName;
         mTitleResId = titleResId;
+        mSummary = summary;
         mFragment = fragment;
         mFragmentArguments = fragmentArguments;
         setWidgetLayoutResource(R.layout.account_type_preference);
 
         setTitle(title);
+        setSummary(summary);
         setIcon(icon);
 
         setOnPreferenceClickListener(this);
@@ -97,8 +111,12 @@
         return false;
     }
 
-    public CharSequence getitle() {
+    public CharSequence getTitle() {
         return mTitle;
     }
 
+    public CharSequence getSummary() {
+        return mSummary;
+    }
+
 }
diff --git a/src/com/android/settings/accounts/ManageAccountsSettings.java b/src/com/android/settings/accounts/ManageAccountsSettings.java
index b124824..abfa6a1 100644
--- a/src/com/android/settings/accounts/ManageAccountsSettings.java
+++ b/src/com/android/settings/accounts/ManageAccountsSettings.java
@@ -373,18 +373,7 @@
             if (mAccountType != null && !account.type.equals(mAccountType)) continue;
             final ArrayList<String> auths = getAuthoritiesForAccountType(account.type);
 
-            boolean showAccount = true;
-            if (mAuthorities != null && auths != null) {
-                showAccount = false;
-                for (String requestedAuthority : mAuthorities) {
-                    if (auths.contains(requestedAuthority)) {
-                        showAccount = true;
-                        break;
-                    }
-                }
-            }
-
-            if (showAccount) {
+            if (AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
                 final Drawable icon = getDrawableForType(account.type);
                 final AccountPreference preference =
                         new AccountPreference(getPrefContext(), account, icon, auths, false);
diff --git a/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java b/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
index aafec37..4808837 100644
--- a/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
+++ b/src/com/android/settings/accounts/UserAndAccountDashboardFragment.java
@@ -17,13 +17,18 @@
 
 import android.content.Context;
 
+import android.os.Bundle;
+import android.support.v7.preference.Preference;
+import android.util.ArraySet;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settingslib.drawer.CategoryKey;
 
+import com.android.settingslib.drawer.Tile;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 import static android.provider.Settings.EXTRA_AUTHORITIES;
@@ -31,6 +36,8 @@
 public class UserAndAccountDashboardFragment extends DashboardFragment {
 
     private static final String TAG = "UserAndAccountDashboard";
+    private static final String METADATA_IA_ACCOUNT = "com.android.settings.ia.account";
+    private HashMap<String, ArraySet<Preference>> mAccountTiles = new HashMap<>();
 
     @Override
     public int getMetricsCategory() {
@@ -71,4 +78,13 @@
         return controllers;
     }
 
-}
+    @Override
+    protected boolean displayTile(Tile tile) {
+        final Bundle metadata = tile.metaData;
+        if (metadata != null) {
+            return metadata.getString(METADATA_IA_ACCOUNT) == null;
+        }
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 28fb851..7dd8346 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -231,6 +231,13 @@
     protected abstract List<PreferenceController> getPreferenceControllers(Context context);
 
     /**
+     * Returns true if this tile should be displayed
+     */
+    protected boolean displayTile(Tile tile) {
+        return true;
+    }
+
+    /**
      * Displays resource based tiles.
      */
     private void displayResourceTiles() {
@@ -319,6 +326,9 @@
                 Log.d(TAG, "tile does not contain a key, skipping " + tile);
                 continue;
             }
+            if (!displayTile(tile)) {
+                continue;
+            }
             if (mDashboardTilePrefKeys.contains(key)) {
                 // Have the key already, will rebind.
                 final Preference preference = mProgressiveDisclosureMixin.findPreference(
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
new file mode 100644
index 0000000..7006dfb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settings.accounts;
+
+import android.os.Bundle;
+
+import com.android.settings.TestConfig;
+import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.Tile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AccountDetailDashboardFragmentTest {
+
+    private static final String METADATA_CATEGORY = "com.android.settings.category";
+    private static final String METADATA_ACCOUNT_TYPE = "com.android.settings.ia.account";
+
+    private AccountDetailDashboardFragment mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment = new AccountDetailDashboardFragment();
+        final Bundle args = new Bundle();
+        args.putString(METADATA_ACCOUNT_TYPE, "com.abc");
+        mFragment.mAccountType = "com.abc";
+    }
+
+    @Test
+    public void testCategory_isAccount() {
+        assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
+    }
+
+    @Test
+    public void refreshDashboardTiles_HasAccountType_shouldDisplay() {
+        final Tile tile = new Tile();
+        final Bundle metaData = new Bundle();
+        metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+        metaData.putString(METADATA_ACCOUNT_TYPE, "com.abc");
+        tile.metaData = metaData;
+
+        assertThat(mFragment.displayTile(tile)).isTrue();
+    }
+
+    @Test
+    public void refreshDashboardTiles_NoAccountType_shouldNotDisplay() {
+        final Tile tile = new Tile();
+        final Bundle metaData = new Bundle();
+        metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+        tile.metaData = metaData;
+
+        assertThat(mFragment.displayTile(tile)).isFalse();
+    }
+
+    @Test
+    public void refreshDashboardTiles_OtherAccountType_shouldNotDisplay() {
+        final Tile tile = new Tile();
+        final Bundle metaData = new Bundle();
+        metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+        metaData.putString(METADATA_ACCOUNT_TYPE, "com.other");
+        tile.metaData = metaData;
+
+        assertThat(mFragment.displayTile(tile)).isFalse();
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index 6e9083b..9ecd1d8 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.os.UserManager;
+import android.os.UserHandle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
@@ -28,6 +29,7 @@
 import android.util.SparseArray;
 
 import com.android.settings.AccessiblePreferenceCategory;
+import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.search.SearchIndexableRaw;
@@ -265,4 +267,37 @@
         assertThat(data.size()).isEqualTo(2);
     }
 
+    @Test
+    @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+    public void onResume_twoAccountsOfSameType_shouldAddThreePreferences() {
+        final List<UserInfo> infos = new ArrayList<>();
+        infos.add(new UserInfo(1, "user 1", 0));
+        when(mUserManager.isManagedProfile()).thenReturn(false);
+        when(mUserManager.isLinkedUser()).thenReturn(false);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+        Account[] accounts = {new Account("Account1", "com.acct1")};
+        when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
+
+        Account[] accountType1 = new Account[2];
+        accountType1[0] = new Account("Account11", "com.acct1");
+        accountType1[1] = new Account("Account12", "com.acct1");
+        when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
+            .thenReturn(accountType1);
+
+        AuthenticatorDescription[] authDescs = {
+            new AuthenticatorDescription("com.acct1", "com.android.settings",
+                R.string.account_settings_title, 0, 0, 0, false)
+        };
+        when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
+
+        AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
+        when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
+            preferenceGroup);
+
+        mController.onResume();
+
+        // should add 2 individual account and the Add account preference
+        verify(preferenceGroup, times(3)).addPreference(any(Preference.class));
+    }
+
 }
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java
new file mode 100644
index 0000000..26c640d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.accounts;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import static org.mockito.Mockito.mock;
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AccountSyncPreferenceControllerTest {
+
+    @Test
+    public void handlePreferenceTreeClick_shouldStartFragment() {
+        final ShadowApplication application = ShadowApplication.getInstance();
+        final Context context = application.getApplicationContext();
+        final Preference preference = new Preference(context);
+        preference.setKey("account_sync");
+        AccountSyncPreferenceController controller = new AccountSyncPreferenceController(context);
+        controller.init(new Account("acct1", "type1"), mock(UserHandle.class));
+
+        controller.handlePreferenceTreeClick(preference);
+
+        assertThat(application.getNextStartedActivity().getStringExtra(
+            SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(AccountSyncSettings.class.getName());
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
index 2d266b6..2df7e2b 100644
--- a/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/UserAndAccountDashboardFragmentTest.java
@@ -15,18 +15,15 @@
  */
 package com.android.settings.accounts;
 
-import android.content.Context;
+import android.os.Bundle;
 
 import com.android.settings.TestConfig;
-import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.Tile;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 
@@ -36,21 +33,39 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class UserAndAccountDashboardFragmentTest {
 
-  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-  private Context mContext;
+    private static final String METADATA_CATEGORY = "com.android.settings.category";
+    private static final String METADATA_ACCOUNT_TYPE = "com.android.settings.ia.account";
 
-  private UserAndAccountDashboardFragment mFragment;
+    private UserAndAccountDashboardFragment mFragment;
 
-  @Before
-  public void setUp() {
-    MockitoAnnotations.initMocks(this);
-    FakeFeatureFactory.setupForTest(mContext);
-    mFragment = new UserAndAccountDashboardFragment();
-  }
+    @Before
+    public void setUp() {
+        mFragment = new UserAndAccountDashboardFragment();
+    }
 
-  @Test
-  public void testCategory_isConnectedDevice() {
-    assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
-  }
+    @Test
+    public void testCategory_isAccount() {
+        assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
+    }
 
+    @Test
+    public void refreshDashboardTiles_HasAccountType_shouldNotDisplay() {
+        final Tile tile = new Tile();
+        final Bundle metaData = new Bundle();
+        metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+        metaData.putString(METADATA_ACCOUNT_TYPE, "com.abc");
+        tile.metaData = metaData;
+
+        assertThat(mFragment.displayTile(tile)).isFalse();
+    }
+
+    @Test
+    public void refreshDashboardTiles_NoAccountType_shouldDisplay() {
+        final Tile tile = new Tile();
+        final Bundle metaData = new Bundle();
+        metaData.putString(METADATA_CATEGORY, CategoryKey.CATEGORY_ACCOUNT);
+        tile.metaData = metaData;
+
+        assertThat(mFragment.displayTile(tile)).isTrue();
+    }
 }