Merge "Update account visibility API."
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 1ad43fa..8185818 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.GET_ACCOUNTS;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
@@ -30,6 +31,8 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.res.Resources;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.database.SQLException;
 import android.os.Build;
 import android.os.Bundle;
@@ -46,6 +49,9 @@
 import com.google.android.collect.Maps;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.SuppressWarnings;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -150,6 +156,7 @@
  * {@link IllegalStateException} if they are used on the main thread.
  */
 public class AccountManager {
+
     private static final String TAG = "AccountManager";
 
     public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
@@ -270,6 +277,54 @@
             "android.accounts.AccountAuthenticator";
     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({VISIBILITY_UNDEFINED, VISIBILITY_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE,
+            VISIBILITY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_NOT_VISIBLE})
+    public @interface AccountVisibility {
+    }
+
+    /**
+     * Account visibility was not set.
+     * @hide
+     */
+    public static final int VISIBILITY_UNDEFINED = 0;
+
+    /**
+     * Account is always visible to given application and only authenticator can revoke visibility.
+     * @hide
+     */
+    public static final int VISIBILITY_VISIBLE = 1;
+
+    /**
+     * Account is visible to given application, but user can revoke visibility.
+     * @hide
+     */
+    public static final int VISIBILITY_USER_MANAGED_VISIBLE = 2;
+
+    /**
+     * Account is not visible to given application and only authenticator can grant visibility.
+     * @hide
+     */
+    public static final int VISIBILITY_NOT_VISIBLE = 3;
+
+    /**
+     * Account is not visible to given application, but user can reveal it, for example, using
+     * {@link #newChooseAccountIntent(Account, List, String[], String, String, String[], Bundle)}
+     * @hide
+     */
+    public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4;
+
+    /**
+     * Key to manifest entry with a list of account types in which application is interested.
+     * Example value: "com.google;com.customtype". If it is  specified then the application
+     * will only get notifications related to the types in the list (see
+     * {@link #ACTION_VISIBLE_ACCOUNTS_CHANGED}). Authenticators managing whitelisted types will be
+     * able to know about the application using {@link #ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED}
+     * @hide
+     */
+    public static final String SUPPORTED_ACCOUNT_TYPES = "android.accounts.SupportedAccountTypes";
+
     /**
      * Token type for the special case where a UID has access only to an account
      * but no authenticator specific auth token types.
@@ -284,16 +339,55 @@
     private final Handler mMainHandler;
 
     /**
-     * Action sent as a broadcast Intent by the AccountsService
-     * when accounts are added, accounts are removed, or an
-     * account's credentials (saved password, etc) are changed.
+     * Action sent as a broadcast Intent by the AccountsService when accounts are added, accounts
+     * are removed, or an account's credentials (saved password, etc) are changed.
      *
      * @see #addOnAccountsUpdatedListener
+     *
+     * Deprecated - use ACTION_VISIBLE_ACCOUNTS_CHANGED instead.
      */
     public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
 
     /**
+     * Action sent as a broadcast Intent by the AccountsService when accounts potentially visible to
+     * the applications are added, accounts are removed, or an account's credentials (saved
+     * password, etc) are changed. List of supported account types shoud be specified in the
+     * Manifest file using {@link #SUPPORTED_ACCOUNT_TYPES}
+     *
+     * @see #addOnAccountsUpdatedListener
+     * @hide
+     */
+    public static final String ACTION_VISIBLE_ACCOUNTS_CHANGED =
+            "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
+
+    /**
+     * Authenticators may subscribe to get notifications about apps interested in their managed account
+     * types using {@link #SUPPORTED_ACCOUNT_TYPES}.
+     * @hide
+     */
+    public static final String ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED =
+            "android.accounts.action.ACCOUNTS_LISTENER_PACKAGE_INSTALLED";
+
+    /**
+     * Uid key to set default visibility for applications targeting API level
+     * {@link android.os.Build.VERSION_CODES#O} or above. See {@link #getAccountVisibility}. If the
+     * value was not set by authenticator USER_MANAGED_NOT_VISIBLE is used.
+     * @hide
+     */
+    public static final int DEFAULT_VISIBILITY = -2;
+
+    /**
+     * Uid key to set visibility for applications targeting API level below
+     * {@link android.os.Build.VERSION_CODES#O}, which were able to see the account before. It
+     * includes applications with GET_ACCOUNTS permission or with the same signature as
+     * authenticator. See {@link #getAccountVisibility}. If the value was not set by authenticator
+     * USER_MANAGED_VISIBLE is used.
+     * @hide
+     */
+    public static final int DEFAULT_LEGACY_VISIBILITY = -3;
+
+    /**
      * @hide
      */
     public AccountManager(Context context, IAccountManager service) {
@@ -346,18 +440,21 @@
     }
 
     /**
-     * Gets the saved password associated with the account.
-     * This is intended for authenticators and related code; applications
-     * should get an auth token instead.
+     * Gets the saved password associated with the account. This is intended for authenticators and
+     * related code; applications should get an auth token instead.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>
+     * It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to have a signature match with the
-     * authenticator that owns the specified account.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs for
-     * this function in API level 22.
+     * <p>
+     * <b>NOTE:</b> If targeting your app to work on API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, AUTHENTICATE_ACCOUNTS
+     * permission is needed for those platforms. See docs for this function in API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
      *
      * @param account The account to query for a password. Must not be {@code null}.
      * @return The account's password, null if none or if the account doesn't exist
@@ -372,19 +469,22 @@
     }
 
     /**
-     * Gets the user data named by "key" associated with the account.
-     * This is intended for authenticators and related code to store
-     * arbitrary metadata along with accounts.  The meaning of the keys
-     * and values is up to the authenticator for the account.
+     * Gets the user data named by "key" associated with the account. This is intended for
+     * authenticators and related code to store arbitrary metadata along with accounts. The meaning
+     * of the keys and values is up to the authenticator for the account.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>
+     * It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to have a signature match with the
-     * authenticator that owns the specified account.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
-     * for this function in API level 22.
+     * <p>
+     * <b>NOTE:</b> If targeting your app to work on API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, AUTHENTICATE_ACCOUNTS
+     * permission is needed for those platforms. See docs for this function in API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
      *
      * @param account The account to query for user data
      * @return The user data, null if the account or key doesn't exist
@@ -440,21 +540,18 @@
     }
 
     /**
-     * Lists all accounts of any type registered on the device.
-     * Equivalent to getAccountsByType(null).
+     * Lists all accounts visible to the caller regardless of type. Equivalent to
+     * getAccountsByType(null). These accounts may be visible because the user granted access to the
+     * account, or the AbstractAcccountAuthenticator managing the account did so or because the
+     * client shares a signature with the managing AbstractAccountAuthenticator.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>
+     * It is safe to call this method from the main thread.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
-     *
-     * @return An array of {@link Account}, one for each account.  Empty
-     *     (never null) if no accounts have been added.
+     * @return An array of {@link Account}, one for each account. Empty (never null) if no accounts
+     *         have been added.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccounts() {
         try {
             return mService.getAccounts(null, mContext.getOpPackageName());
@@ -465,21 +562,16 @@
 
     /**
      * @hide
-     * Lists all accounts of any type registered on the device for a given
-     * user id. Equivalent to getAccountsByType(null).
+     * Lists all accounts visible to caller regardless of type for a given user id. Equivalent to
+     * getAccountsByType(null).
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>
+     * It is safe to call this method from the main thread.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
-     *
-     * @return An array of {@link Account}, one for each account.  Empty
-     *     (never null) if no accounts have been added.
+     * @return An array of {@link Account}, one for each account. Empty (never null) if no accounts
+     *         have been added.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsAsUser(int userId) {
         try {
             return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
@@ -524,29 +616,41 @@
     }
 
     /**
-     * Lists all accounts of a particular type.  The account type is a
-     * string token corresponding to the authenticator and useful domain
-     * of the account.  For example, there are types corresponding to Google
-     * and Facebook.  The exact string token to use will be published somewhere
-     * associated with the authenticator in question.
+     * Lists all accounts of particular type visible to the caller. These accounts may be visible
+     * because the user granted access to the account, or the AbstractAcccountAuthenticator managing
+     * the account did so or because the client shares a signature with the managing
+     * AbstractAccountAuthenticator.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>
+     * The account type is a string token corresponding to the authenticator and useful domain of
+     * the account. For example, there are types corresponding to Google and Facebook. The exact
+     * string token to use will be published somewhere associated with the authenticator in
+     * question.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p>
+     * It is safe to call this method from the main thread.
      *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
-     * or signature match. See docs for this function in API level 22.
+     * <p>
+     * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
+     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
+     *
+     * <p>
+     * Caller targeting API level below {@link android.os.Build.VERSION_CODES#O} that have not been
+     * granted the {@link android.Manifest.permission#GET_ACCOUNTS} permission, will only see those
+     * accounts managed by AbstractAccountAuthenticators whose signature matches the client.
+     *
+     * <p>
+     * <b>NOTE:</b> If targeting your app to work on API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+     * needed for those platforms, irrespective of uid or signature match. See docs for this
+     * function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
      *
      * @param type The type of accounts to return, null to retrieve all accounts
-     * @return An array of {@link Account}, one per matching account.  Empty
-     *     (never null) if no accounts of the specified type have been added.
+     * @return An array of {@link Account}, one per matching account. Empty (never null) if no
+     *         accounts of the specified type have been added.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsByType(String type) {
         return getAccountsByTypeAsUser(type, Process.myUserHandle());
     }
@@ -612,30 +716,28 @@
     }
 
     /**
-     * Finds out whether a particular account has all the specified features.
-     * Account features are authenticator-specific string tokens identifying
-     * boolean account properties.  For example, features are used to tell
-     * whether Google accounts have a particular service (such as Google
-     * Calendar or Google Talk) enabled.  The feature names and their meanings
-     * are published somewhere associated with the authenticator in question.
+     * Finds out whether a particular account has all the specified features. Account features are
+     * authenticator-specific string tokens identifying boolean account properties. For example,
+     * features are used to tell whether Google accounts have a particular service (such as Google
+     * Calendar or Google Talk) enabled. The feature names and their meanings are published
+     * somewhere associated with the authenticator in question.
      *
-     * <p>This method may be called from any thread, but the returned
-     * {@link AccountManagerFuture} must not be used on the main thread.
+     * <p>
+     * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
+     * not be used on the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
-     * match with the AbstractAccountAuthenticator that manages the account.
+     * <p>
+     * If caller target API level is below {@link android.os.Build.VERSION_CODES#O}, it is
+     * required to hold the permission {@link android.Manifest.permission#GET_ACCOUNTS} or have a
+     * signature match with the AbstractAccountAuthenticator that manages the account.
      *
      * @param account The {@link Account} to test
      * @param features An array of the account features to check
-     * @param callback Callback to invoke when the request completes,
-     *     null for no callback
-     * @param handler {@link Handler} identifying the callback thread,
-     *     null for the main thread
-     * @return An {@link AccountManagerFuture} which resolves to a Boolean,
-     * true if the account exists and has all of the specified features.
+     * @param callback Callback to invoke when the request completes, null for no callback
+     * @param handler {@link Handler} identifying the callback thread, null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Boolean, true if the account
+     *         exists and has all of the specified features.
      */
-    @RequiresPermission(GET_ACCOUNTS)
     public AccountManagerFuture<Boolean> hasFeatures(final Account account,
             final String[] features,
             AccountManagerCallback<Boolean> callback, Handler handler) {
@@ -657,40 +759,42 @@
     }
 
     /**
-     * Lists all accounts of a type which have certain features.  The account
-     * type identifies the authenticator (see {@link #getAccountsByType}).
-     * Account features are authenticator-specific string tokens identifying
-     * boolean account properties (see {@link #hasFeatures}).
+     * Lists all accounts of a type which have certain features. The account type identifies the
+     * authenticator (see {@link #getAccountsByType}). Account features are authenticator-specific
+     * string tokens identifying boolean account properties (see {@link #hasFeatures}).
      *
-     * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
-     * which may contact the server or do other work to check account features,
-     * so the method returns an {@link AccountManagerFuture}.
+     * <p>
+     * Unlike {@link #getAccountsByType}, this method calls the authenticator, which may contact the
+     * server or do other work to check account features, so the method returns an
+     * {@link AccountManagerFuture}.
      *
-     * <p>This method may be called from any thread, but the returned
-     * {@link AccountManagerFuture} must not be used on the main thread.
+     * <p>
+     * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
+     * not be used on the main thread.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p>
+     * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
+     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
+     *
+     * <p>
+     * Caller targeting API level below {@link android.os.Build.VERSION_CODES#O} that have not been
+     * granted the {@link android.Manifest.permission#GET_ACCOUNTS} permission, will only see those
+     * accounts managed by AbstractAccountAuthenticators whose signature matches the client.
+     * <p>
+     * <b>NOTE:</b> If targeting your app to work on API level
+     * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and before, GET_ACCOUNTS permission is
+     * needed for those platforms, irrespective of uid or signature match. See docs for this
+     * function in API level {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
+     *
      *
      * @param type The type of accounts to return, must not be null
-     * @param features An array of the account features to require,
-     *     may be null or empty
-     *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
-     * or signature match. See docs for this function in API level 22.
-     *
-     * @param callback Callback to invoke when the request completes,
-     *     null for no callback
-     * @param handler {@link Handler} identifying the callback thread,
-     *     null for the main thread
-     * @return An {@link AccountManagerFuture} which resolves to an array of
-     *     {@link Account}, one per account of the specified type which
-     *     matches the requested features.
+     * @param features An array of the account features to require, may be null or empty *
+     * @param callback Callback to invoke when the request completes, null for no callback
+     * @param handler {@link Handler} identifying the callback thread, null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to an array of {@link Account}, one
+     *         per account of the specified type which matches the requested features.
      */
-    @RequiresPermission(GET_ACCOUNTS)
     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
             final String type, final String[] features,
             AccountManagerCallback<Account[]> callback, Handler handler) {
@@ -751,33 +855,70 @@
     }
 
     /**
-     * Adds an account directly to the AccountManager. Additionally this
-     * makes the Account visible to desired UIDs of applications on the device,
-     * and sends directed broadcasts to these individual applications.
-     * <p>Normally used by sign-up wizards associated with authenticators, not
-     *  directly by applications.
-     * <p>Calling this method does not update the last authenticated timestamp,
-     * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
+     * Adds an account directly to the AccountManager. Additionally this makes the Account visible
+     * to desired UIDs of applications on the device, and sends directed broadcasts to these
+     * individual applications.
+     * <p>
+     * Normally used by sign-up wizards associated with authenticators, not directly by
+     * applications.
+     * <p>
+     * Calling this method does not update the last authenticated timestamp, referred by
+     * {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
      * {@link #notifyAccountAuthenticated(Account)} after getting success.
-     * <p>It is safe to call this method from the main thread.
-     * <p>This method requires the caller to have a signature match with the
-     * authenticator that owns the specified account.
+     * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
      * @param account The {@link Account} to add
      * @param password The password to associate with the account, null for none
-     * @param extras String values to use for the account's userdata, null for
-     *            none
-     * @param selectedUids Array of uids whose associated applications can access
-     * this account without any additional user approval.
+     * @param extras String values to use for the account's userdata, null for none
+     * @param selectedUids Array of uids whose associated applications can access this account
+     *        without any additional user approval.
      *
-     * @return True if the account was successfully added, false if the account
-     *         already exists, the account is null, or another error occurs.
+     * @return True if the account was successfully added, false if the account already exists, the
+     *         account is null, or another error occurs.
      */
     public boolean addAccountExplicitly(Account account, String password, Bundle extras,
-                int[] selectedUids) {
-        if (account == null) throw new IllegalArgumentException("account is null");
+            int[] selectedUids) {
+        return false; // TODO remove this method.
+    }
+
+    /**
+     * Adds an account directly to the AccountManager. Additionally this makes the Account visible
+     * to desired UIDs of applications on the device, and sends directed broadcasts to these
+     * individual applications.
+     * <p>
+     * Normally used by sign-up wizards associated with authenticators, not directly by
+     * applications.
+     * <p>
+     * Calling this method does not update the last authenticated timestamp, referred by
+     * {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
+     * {@link #notifyAccountAuthenticated(Account)} after getting success.
+     * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
+     *
+     * @param account The {@link Account} to add
+     * @param password The password to associate with the account, null for none
+     * @param extras String values to use for the account's userdata, null for none
+     * @param visibility Map from uid to visibility values which will be set before account is
+     *        added. See getAccountVisibility for possilbe values.
+     *
+     * @return True if the account was successfully added, false if the account already exists, the
+     *         account is null, or another error occurs.
+     * @hide
+     */
+    public boolean addAccountExplicitly(Account account, String password, Bundle extras,
+            Map<Integer, Integer> visibility) {
+        if (account == null)
+            throw new IllegalArgumentException("account is null");
         try {
-            return mService.addAccountExplicitlyWithUid(account, password, extras, selectedUids);
+            return mService.addAccountExplicitlyWithVisibility(account, password, extras,
+                    visibility);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -803,9 +944,37 @@
     }
 
     /**
+     * Gets all accounts of given type and their visibility for specific package. This method
+     * requires the caller to have a signature match with the authenticator that manages
+     * accountType. It is a helper method which combines calls to {@link #getAccountsByType} by
+     * authenticator and {@link #getAccountVisibility} for every returned account.
+     *
+     * <p>
+     *
+     * @param packageName Package name.
+     * @param accountType Account type.
+     *
+     * @return Map with visibility for all accounts of given type. See {@link #getAccountVisibility}
+     *         for possilbe values.
+     * @hide
+     */
+    public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
+            String accountType) {
+        try {
+            @SuppressWarnings("unchecked")
+            Map<Account, Integer> result = (Map<Account, Integer>) mService
+                    .getAccountsAndVisibilityForPackage(packageName, accountType);
+            return result;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gives a certain UID, represented a application, access to an account
-     * <p>This method requires the caller to have a signature match with the authenticator
-     * that owns the specified account.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
      * @param account Account to make visible.
      * @param uid The UID of the application to add account access.
@@ -814,18 +983,18 @@
      */
     public boolean makeAccountVisible(Account account, int uid) {
         try {
-            return mService.makeAccountVisible(account, uid);
+            return mService.setAccountVisibility(account, uid, VISIBILITY_USER_MANAGED_VISIBLE);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Removes visibility of certain account of a process identified
-     * by a given UID to an application.
-     * This is called by the Authenticator.
-     * <p>This method requires the caller to have a signature match with the authenticator
-     * that owns the specified account.
+     * Removes visibility of certain account of a process identified by a given UID to an
+     * application. This is called by the Authenticator.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
      * @param account Remove visibility of this account..
      * @param uid The UID of the application to remove account access.
@@ -834,17 +1003,18 @@
      */
     public boolean removeAccountVisibility(Account account, int uid) {
         try {
-            return mService.removeAccountVisibility(account, uid);
+            return mService.setAccountVisibility(account, uid, VISIBILITY_USER_MANAGED_NOT_VISIBLE);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Checks visibility of certain account of a process identified
-     * by a given UID. This is called by the Authenticator.
-     * <p>This method requires the caller to have a signature match with the authenticator
-     * that owns the specified account.
+     * Checks visibility of certain account of a process identified by a given UID. This is called
+     * by the Authenticator.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
      * @param account Account to check visibility.
      * @param uid The UID of the application to check account access.
@@ -853,7 +1023,60 @@
      */
     public boolean isAccountVisible(Account account, int uid) {
         try {
-            return mService.isAccountVisible(account, uid);
+            Integer visibility = mService.getAccountVisibility(account, uid);
+            return visibility == VISIBILITY_USER_MANAGED_NOT_VISIBLE
+                    || visibility == VISIBILITY_VISIBLE;
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set visibility value of given account to certain UID.
+     * <p>
+     * See {@link #getAccountVisibility} for possible values.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
+     *
+     * @param account Account to make visible.
+     * @param uid The UID of the application to modify account visibility.
+     * @param visibility - new visibility value.
+     *
+     * @return True if visibility value was succesfully updated.
+     * @hide
+     */
+    public boolean setAccountVisibility(Account account, int uid,
+            @AccountVisibility int visibility) {
+        try {
+            return mService.setAccountVisibility(account, uid, visibility);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets visibility of certain account for given UID. Possible returned values are:
+     * <ul>
+     * <li>{@link #VISIBILITY_VISIBLE}</li>
+     * <li>{@link #VISIBILITY_USER_MANAGED_VISIBLE}</li>
+     * <li>{@link #VISIBILITY_NOT_VISIBLE}
+     * <li>{@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE}</li>
+     * </ul>
+     *
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
+     *
+     * @param account Account to get visibility.
+     * @param uid The UID of the application to get account visibility.
+     *
+     * @return int Visibility for given account and uid.
+     * @hide
+     */
+    public @AccountVisibility int getAccountVisibility(Account account, int uid) {
+        try {
+            return mService.getAccountVisibility(account, uid);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -2428,6 +2651,9 @@
                                     };
                                     // have many accounts, launch the chooser
                                     Intent intent = new Intent();
+                                    // TODO - this activity will not include
+                                    // USER_MANAGED_NOT_VISIBLE
+                                    // accounts. We need to move method to service
                                     ComponentName componentName = ComponentName.unflattenFromString(
                                             Resources.getSystem().getString(
                                                     R.string.config_chooseAccountActivity));
@@ -2483,58 +2709,57 @@
     }
 
     /**
-     * This convenience helper combines the functionality of
-     * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
-     * {@link #addAccount}.
+     * This convenience helper combines the functionality of {@link #getAccountsByTypeAndFeatures},
+     * {@link #getAuthToken}, and {@link #addAccount}.
      *
-     * <p>This method gets a list of the accounts matching the
-     * specified type and feature set; if there is exactly one, it is
-     * used; if there are more than one, the user is prompted to pick one;
-     * if there are none, the user is prompted to add one.  Finally,
-     * an auth token is acquired for the chosen account.
+     * <p>
+     * This method gets a list of the accounts matching specific type and feature set which are
+     * visible to the caller or for which user can grant access (see {@link #getAccountsByType} for
+     * details); if there is exactly one already visible account, it is used; if there are some
+     * accounts for which user grant visibility, the user is prompted to pick one; if there are
+     * none, the user is prompted to add one. Finally, an auth token is acquired for the chosen
+     * account.
      *
-     * <p>This method may be called from any thread, but the returned
-     * {@link AccountManagerFuture} must not be used on the main thread.
+     * <p>
+     * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
+     * not be used on the main thread.
      *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
-     * this function in API level 22.
+     * <p>
+     * <b>NOTE:</b> If targeting your app to work on API level 22 and before, MANAGE_ACCOUNTS
+     * permission is needed for those platforms. See docs for this function in API level 22.
      *
-     * @param accountType The account type required
-     *     (see {@link #getAccountsByType}), must not be null
-     * @param authTokenType The desired auth token type
-     *     (see {@link #getAuthToken}), must not be null
-     * @param features Required features for the account
-     *     (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
-     * @param activity The {@link Activity} context to use for launching new
-     *     sub-Activities to prompt to add an account, select an account,
-     *     and/or enter a password, as necessary; used only to call
-     *     startActivity(); should not be null
-     * @param addAccountOptions Authenticator-specific options to use for
-     *     adding new accounts; may be null or empty
-     * @param getAuthTokenOptions Authenticator-specific options to use for
-     *     getting auth tokens; may be null or empty
-     * @param callback Callback to invoke when the request completes,
-     *     null for no callback
-     * @param handler {@link Handler} identifying the callback thread,
-     *     null for the main thread
-     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
-     *     at least the following fields:
-     * <ul>
-     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
-     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
-     * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
-     * </ul>
+     * @param accountType The account type required (see {@link #getAccountsByType}), must not be
+     *        null
+     * @param authTokenType The desired auth token type (see {@link #getAuthToken}), must not be
+     *        null
+     * @param features Required features for the account (see
+     *        {@link #getAccountsByTypeAndFeatures}), may be null or empty
+     * @param activity The {@link Activity} context to use for launching new sub-Activities to
+     *        prompt to add an account, select an account, and/or enter a password, as necessary;
+     *        used only to call startActivity(); should not be null
+     * @param addAccountOptions Authenticator-specific options to use for adding new accounts; may
+     *        be null or empty
+     * @param getAuthTokenOptions Authenticator-specific options to use for getting auth tokens; may
+     *        be null or empty
+     * @param callback Callback to invoke when the request completes, null for no callback
+     * @param handler {@link Handler} identifying the callback thread, null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Bundle with at least the
+     *         following fields:
+     *         <ul>
+     *         <li>{@link #KEY_ACCOUNT_NAME} - the name of the account
+     *         <li>{@link #KEY_ACCOUNT_TYPE} - the type of the account
+     *         <li>{@link #KEY_AUTHTOKEN} - the auth token you wanted
+     *         </ul>
      *
-     * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
-     * <ul>
-     * <li> {@link AuthenticatorException} if no authenticator was registered for
-     *      this account type or the authenticator failed to respond
-     * <li> {@link OperationCanceledException} if the operation was canceled for
-     *      any reason, including the user canceling any operation
-     * <li> {@link IOException} if the authenticator experienced an I/O problem
-     *      updating settings, usually because of network trouble
-     * </ul>
+     *         If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+     *         <ul>
+     *         <li>{@link AuthenticatorException} if no authenticator was registered for this
+     *         account type or the authenticator failed to respond
+     *         <li>{@link OperationCanceledException} if the operation was canceled for any reason,
+     *         including the user canceling any operation
+     *         <li>{@link IOException} if the authenticator experienced an I/O problem updating
+     *         settings, usually because of network trouble
+     *         </ul>
      */
     public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
             final String accountType, final String authTokenType, final String[] features,
@@ -2689,33 +2914,33 @@
     };
 
     /**
-     * Adds an {@link OnAccountsUpdateListener} to this instance of the
-     * {@link AccountManager}.  This listener will be notified whenever the
-     * list of accounts on the device changes.
+     * Adds an {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}. This
+     * listener will be notified whenever user or AbstractAcccountAuthenticator made changes to
+     * accounts related to the caller - either list of accounts returned by {@link #getAccounts()}
+     * was changed, or new account was added for which user can grant access to the caller.
      *
-     * <p>As long as this listener is present, the AccountManager instance
-     * will not be garbage-collected, and neither will the {@link Context}
-     * used to retrieve it, which may be a large Activity instance.  To avoid
-     * memory leaks, you must remove this listener before then.  Normally
-     * listeners are added in an Activity or Service's {@link Activity#onCreate}
-     * and removed in {@link Activity#onDestroy}.
+     * <p>
+     * As long as this listener is present, the AccountManager instance will not be
+     * garbage-collected, and neither will the {@link Context} used to retrieve it, which may be a
+     * large Activity instance. To avoid memory leaks, you must remove this listener before then.
+     * Normally listeners are added in an Activity or Service's {@link Activity#onCreate} and
+     * removed in {@link Activity#onDestroy}.
      *
-     * <p>The listener will only be informed of accounts that would be returned
-     * to the caller via {@link #getAccounts()}. Typically this means that to
-     * get any accounts, the caller will need to be grated the GET_ACCOUNTS
-     * permission.
      *
-     * <p>It is safe to call this method from the main thread.
+     * If SUPPORTED_ACCOUNT_TYPES is specified in the manifest file, listener will only be
+     * notified about whitelisted types.
+     *
+     * <p>
+     * It is safe to call this method from the main thread.
      *
      * @param listener The listener to send notifications to
-     * @param handler {@link Handler} identifying the thread to use
-     *     for notifications, null for the main thread
-     * @param updateImmediately If true, the listener will be invoked
-     *     (on the handler thread) right away with the current account list
+     * @param handler {@link Handler} identifying the thread to use for notifications, null for the
+     *        main thread
+     * @param updateImmediately If true, the listener will be invoked (on the handler thread) right
+     *        away with the current account list
      * @throws IllegalArgumentException if listener is null
      * @throws IllegalStateException if listener was already added
      */
-    @RequiresPermission(GET_ACCOUNTS)
     public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
             Handler handler, boolean updateImmediately) {
         if (listener == null) {
@@ -2729,22 +2954,47 @@
 
             mAccountsUpdatedListeners.put(listener, handler);
 
+
             if (wasEmpty) {
                 // Register a broadcast receiver to monitor account changes
                 IntentFilter intentFilter = new IntentFilter();
-                intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
+                if (isVisibleAccountsChangedBroadcastSupported()) {
+                    intentFilter.addAction(ACTION_VISIBLE_ACCOUNTS_CHANGED);
+                } else {
+                    intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
+                }
                 // To recover from disk-full.
                 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
+                // Register a broadcast receiver to monitor account changes
                 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
             }
         }
-
         if (updateImmediately) {
             postToHandler(handler, listener, getAccounts());
         }
     }
 
     /**
+     * @hide
+     */
+    private boolean isVisibleAccountsChangedBroadcastSupported() {
+        String interestedTypes = null;
+        try {
+            String packageName = mContext.getOpPackageName();
+            ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(packageName,
+                    PackageManager.GET_META_DATA);
+            Bundle b = ai.metaData;
+            if (b == null) {
+                return false;
+            }
+            interestedTypes = b.getString(SUPPORTED_ACCOUNT_TYPES);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+        return !TextUtils.isEmpty(interestedTypes);
+    }
+
+    /**
      * Removes an {@link OnAccountsUpdateListener} previously registered with
      * {@link #addOnAccountsUpdatedListener}.  The listener will no longer
      * receive notifications of account changes.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index fc10990..66c3ca3 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -24,6 +24,8 @@
 import android.os.RemoteCallback;
 import android.os.UserHandle;
 
+import java.util.Map;
+
 /**
  * Central application service that provides account management.
  * @hide
@@ -106,18 +108,17 @@
     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
         String statusToken);
 
-    /* Allows Authenticator to view what packages or UIDs on phone have requested it. */
+    /* Allows Authenticator to get UIDs of packages which registered to receive updates about given account type.*/
     int[] getRequestingUidsForType(String accountType);
 
-    /* Allows authenticator to add an account explicitly that is only visible to
-     certain uids; the authenticator learns of these UIDs */
-    boolean addAccountExplicitlyWithUid(in Account account, String password, in Bundle extras,
-            in int[] selectedUids);
+    boolean addAccountExplicitlyWithVisibility(in Account account, String password, in Bundle extras,
+            in Map visibility);
 
-    /* Controls visibility of UIDs of applications to Accounts */
-    boolean removeAccountVisibility(in Account a, in int uid);
-    boolean makeAccountVisible(in Account a, in int uid);
-    boolean isAccountVisible(in Account a, in int uid);
+    boolean setAccountVisibility(in Account a, int uid, int newVisibility);
+    int getAccountVisibility(in Account a, int uid);
+
+    /* Type may be null  returns Map <Account, Integer>*/
+    Map getAccountsAndVisibilityForPackage(in String packageName, in String accountType);
 
     /* Check if the package in a user can access an account */
     boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index c65aed7..11e1a9d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -201,25 +201,9 @@
         private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
         /** protected by the {@link #cacheLock} */
         private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
-
         /** protected by the {@link #cacheLock} */
         private final TokenCache accountTokenCaches = new TokenCache();
 
-        /** protected by the {@link #cacheLock} */
-        private final Map<String, ArrayList<Integer>> mApplicationAccountRequestMappings =
-                new HashMap<>();
-
-        /* Together the below two Sparse Arrays serve as visible list. One maps UID to account
-        number. Another maps Account number to Account.*/
-
-        /** protected by the {@link #cacheLock} */
-        private final SparseArray<ArrayList<Integer>> mVisibleListUidToMockAccountNumbers =
-                new SparseArray<>();
-
-        //TODO: Instead of using Mock Account IDs, use the actual account IDs.
-        /** protected by the {@link #cacheLock} */
-        private final SparseArray<Account> mMockAccountIdToAccount = new SparseArray<>();
-
         /**
          * protected by the {@link #cacheLock}
          *
@@ -301,20 +285,7 @@
                         @Override
                         public void run() {
                             purgeOldGrantsAll();
-
-                            /* clears application request's for account types supported */
-                            int uidOfUninstalledApplication =
-                                    intent.getIntExtra(Intent.EXTRA_UID, -1);
-                            if(uidOfUninstalledApplication != -1) {
-                                clearRequestedAccountVisibility(uidOfUninstalledApplication,
-                                        getUserAccounts(UserHandle.getUserId(
-                                        uidOfUninstalledApplication)));
-                            }
-
-                            /* removes visibility of previous UID of this uninstalled application*/
-                            removeAccountVisibilityAllAccounts(uidOfUninstalledApplication,
-                                        getUserAccounts(UserHandle.getUserId(
-                                        uidOfUninstalledApplication)));
+                            // TODO remove visibility entries.
                         }
                     };
                     mHandler.post(purgingRunnable);
@@ -472,18 +443,20 @@
     }
 
     @Override
-    public boolean addAccountExplicitlyWithUid(Account account, String password, Bundle extras,
-            int[] selectedUids) {
-        if(addAccountExplicitly(account,password,extras)) {
-            for(int thisUid : selectedUids) {
-                makeAccountVisible(account, thisUid);
-            }
-            return true;
-        }
+    public boolean addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras,
+            Map uidToVisibility) {
+        // TODO implementation
         return false;
     }
 
     @Override
+    public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
+            String accountType) {
+        // TODO Implement.
+        return new HashMap<Account, Integer>();
+    }
+
+    @Override
     public int[] getRequestingUidsForType(String accountType) {
         int callingUid = Binder.getCallingUid();
         if (!isAccountManagedByCaller(accountType, callingUid, UserHandle.getUserId(callingUid))) {
@@ -493,204 +466,23 @@
                     accountType);
             throw new SecurityException(msg);
         }
-        return getRequestingUidsForType(accountType, getUserAccounts(
-                UserHandle.getUserId(callingUid)));
-    }
-
-    /**
-     * Returns all UIDs for applications that requested the account type. This method
-     * is called indirectly by the Authenticator and AccountManager
-     *
-     * @param accountType authenticator would like to know the requesting apps of
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return ArrayList of all UIDs that support accounts of this
-     * account type that seek approval (to be used to know which accounts for
-     * the authenticator to include in addAccountExplicitly). Null if none.
-     */
-    private int[] getRequestingUidsForType(String accountType, UserAccounts ua) {
-        synchronized(ua.cacheLock) {
-            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
-                    ua.mApplicationAccountRequestMappings;
-            ArrayList<Integer> allUidsForAccountType = userApplicationAccountRequestMappings.get(
-                    accountType);
-            if(allUidsForAccountType == null) {
-                return null;
-            }
-            int[] toReturn = new int[allUidsForAccountType.size()];
-            for(int i = 0 ; i < toReturn.length ; i++) {
-                toReturn[i] = allUidsForAccountType.get(i);
-            }
-            return toReturn;
-        }
+        // TODO Implement.
+        return new int[]{};
     }
 
     @Override
-    public boolean isAccountVisible(Account a, int uid) {
-        int callingUid = Binder.getCallingUid();
-        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
-            String msg = String.format(
-                    "uid %s cannot get secrets for accounts of type: %s",
-                    callingUid,
-                    a.type);
-            throw new SecurityException(msg);
-        }
-        return isAccountVisible(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
-    }
-
-    /**
-     * Checks visibility of certain account of a process identified
-     * by a given UID. This is called by the Authenticator indirectly.
-     *
-     * @param a The account to check visibility of
-     * @param uid UID to check visibility of
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return True if application has access to the account
-     *
-     */
-    private boolean isAccountVisible(Account a, int uid, UserAccounts ua) {
-        if(isAccountManagedByCaller(a.type, uid, UserHandle.getUserId(uid))) {
-            return true;
-        }
-        int accountMapping = getMockAccountNumber(a, ua);
-        if(accountMapping < 0) {
-            return true;
-        }
-        synchronized(ua.cacheLock) {
-            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
-            int indexOfAccountMapping = userAcctIdToAcctMap.indexOfValueByValue(a);
-            return indexOfAccountMapping == -1 || (linkedAccountsToUid != null
-                    && linkedAccountsToUid.contains(accountMapping));
-        }
+    public int getAccountVisibility(Account a, int uid) {
+        // TODO Implement.
+        return 0;
     }
 
     @Override
-    public boolean makeAccountVisible(Account a, int uid) {
-        int callingUid = Binder.getCallingUid();
-        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
-            String msg = String.format(
-                    "uid %s cannot get secrets for accounts of type: %s",
-                    callingUid,
-                    a.type);
-            throw new SecurityException(msg);
-        }
-        return makeAccountVisible(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
-    }
-
-    /**
-     * Gives a certain UID, represented a application, access to an account. This method
-     * is called indirectly by the Authenticator.
-     *
-     * @param a Account to make visible
-     * @param uid to add visibility of the Account from
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return True if account made visible to application and was not previously visible.
-     */
-    private boolean makeAccountVisible(Account a, int uid, UserAccounts ua) {
-        int accountMapping = getMockAccountNumber(a, ua);
-        if(accountMapping < 0) {
-            accountMapping = makeAccountNumber(a, ua);
-        }
-        synchronized(ua.cacheLock) {
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
-            if(linkedAccountsToUid == null) {
-                linkedAccountsToUid = new ArrayList<>();
-                linkedAccountsToUid.add(accountMapping);
-                userWlUidToMockAccountNums.put(uid, linkedAccountsToUid);
-            } else if(!linkedAccountsToUid.contains(accountMapping)) {
-                linkedAccountsToUid.add(accountMapping);
-            } else {
-                return false;
-            }
-        }
-
-        String[] subPackages = mPackageManager.getPackagesForUid(uid);
-        if(subPackages != null) {
-            for(String subPackage : subPackages) {
-                sendNotification(subPackage, a);
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean removeAccountVisibility(Account a, int uid) {
-        int callingUid = Binder.getCallingUid();
-        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
-            String msg = String.format(
-                    "uid %s cannot get secrets for accounts of type: %s",
-                    callingUid,
-                    a.type);
-            throw new SecurityException(msg);
-        }
-        return removeAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
-    }
-
-    /**
-     * Removes visibility of certain account of a process identified
-     * by a given UID to an application. This is called directly by the
-     * AccountManager and indirectly by the Authenticator.
-     *
-     * @param a Account to remove visibility from
-     * @param uid UID to remove visibility of the Account from
-     * @param ua UserAccount that hosts the account and application
-     *
-     * @return True if application access to account removed and was previously visible.
-     */
-    private boolean removeAccountVisibility(Account a, int uid, UserAccounts ua) {
-        int accountMapping = getMockAccountNumber(a, ua);
-        if(accountMapping < 0) {
-            return false;
-        }
-        synchronized(ua.cacheLock) {
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
-            if(linkedAccountsToUid != null) {
-                boolean toReturn = linkedAccountsToUid.remove((Integer) accountMapping);
-                if(linkedAccountsToUid.size() == 0) {
-                    userWlUidToMockAccountNums.remove(uid);
-                }
-                return toReturn;
-            }
-        }
+    public boolean setAccountVisibility(Account a, int uid, int visibility) {
+        // TODO Implement.
         return false;
     }
 
     /**
-     * Registers an application's preferences for supported account types for login. This is
-     * a helper method of requestAccountVisibility and indirectly called by AccountManager.
-     *
-     * @param accountTypes account types third party app is willing to support
-     * @param uid of application requesting account visibility
-     * @param ua UserAccount that hosts the account and application
-     */
-    private void addRequestedAccountsVisibility(String[] accountTypes, int uid, UserAccounts ua) {
-        synchronized(ua.cacheLock) {
-            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
-                    ua.mApplicationAccountRequestMappings;
-            for(String accountType : accountTypes) {
-                ArrayList<Integer> accountUidAppList = userApplicationAccountRequestMappings
-                        .get(accountType);
-                if(accountUidAppList == null) {
-                    accountUidAppList = new ArrayList<>();
-                    accountUidAppList.add(uid);
-                    userApplicationAccountRequestMappings.put(accountType, accountUidAppList);
-                } else if (!accountUidAppList.contains(uid)) {
-                    accountUidAppList.add(uid);
-                }
-            }
-        }
-    }
-
-    /**
      * Registers the requested login account types requested by all the applications already
      * installed on the device.
      */
@@ -706,124 +498,8 @@
     }
 
     /**
-     * Clears all preferences an application had for login account types it offered
-     * support for. This method is used by AccountManager after application is
-     * uninstalled.
-     *
-     * @param uid Uid of the application to clear account type preferences
-     * @param ua UserAccount that hosted the account and application
-     *
-     * @return true if any previous settings were overridden.
-     */
-    private boolean clearRequestedAccountVisibility(int uid, UserAccounts ua) {
-        boolean accountsDeleted = false;
-        ArrayList<String> accountTypesToRemove = new ArrayList<>();
-        synchronized(ua.cacheLock) {
-            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
-                    ua.mApplicationAccountRequestMappings;
-            Set<Entry<String, ArrayList<Integer>>> accountTypeAppListEntries =
-                    userApplicationAccountRequestMappings.entrySet();
-
-            for(Entry<String, ArrayList<Integer>> entry : accountTypeAppListEntries) {
-                ArrayList<Integer> supportedApps = entry.getValue();
-                if(supportedApps.remove((Integer) uid)) {
-                    accountsDeleted = true;
-                }
-
-                if(supportedApps.isEmpty()) {
-                    accountTypesToRemove.add(entry.getKey());
-                }
-            }
-
-            for(String s : accountTypesToRemove) {
-                userApplicationAccountRequestMappings.remove(s);
-            }
-        }
-
-        return accountsDeleted;
-    }
-
-    /**
-     * Retrieves the mock account number associated with an Account in order to later retrieve
-     * the account from the Integer-Account Mapping. An account number is not the same as
-     * accountId in the database. This method can be indirectly called by AccountManager and
-     * indirectly by the Authenticator.
-     *
-     * @param a account to retrieve account number mapping
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return account number affiliated with the Account in question. Negative number if none.
-     */
-    private int getMockAccountNumber(Account a, UserAccounts ua) {
-    //TODO: Each account is linked to AccountId rather than generated mock account numbers
-        SparseArray<Account> userAcctIdToAcctMap =
-                ua.mMockAccountIdToAccount;
-            synchronized(ua.cacheLock) {
-                int indexOfAccount = userAcctIdToAcctMap.indexOfValueByValue(a);
-                if(indexOfAccount < 0) {
-                    return -1;
-                }
-                return userAcctIdToAcctMap.keyAt(indexOfAccount);
-            }
-    }
-
-    /**
-     * Returns a full list of accounts that a certain UID is allowed access
-     * based on the visible list entries.
-     *
-     * @param uid of application to retrieve visible listed accounts for
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return array of Account values that are accessible by the given uids
-     */
-    private Account[] getVisibleListedAccounts(int uid, UserAccounts ua) {
-        ArrayList<Account> visibleListedAccounts = new ArrayList<>();
-        synchronized(ua.cacheLock) {
-            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            ArrayList<Integer> visibleListedUidAccountNumbers =
-                    userWlUidToMockAccountNums.get(uid);
-            if(visibleListedUidAccountNumbers != null) {
-                for(Integer accountNumber : visibleListedUidAccountNumbers) {
-                    Account currentAccount = userAcctIdToAcctMap.get(accountNumber);
-                    visibleListedAccounts.add(currentAccount);
-                }
-            }
-        }
-        Account[] arrVisibleListedAccounts = new Account[visibleListedAccounts.size()];
-        return visibleListedAccounts.toArray(arrVisibleListedAccounts);
-    }
-
-    /**
-     * Makes an account number for a given Account to be mapped to.
-     * This method is called by makeVisible if an Account does not have
-     * a mapping for the visible list. This method is thus indirectly
-     * called by the Authenticator.
-     *
-     * @param a account to make an account number mapping of
-     * @param ua UserAccount that currently hosts the account and application
-     *
-     * @return account number created to map to the given account
-     */
-    // TODO: Remove this method and use accountId from DB.
-    private int makeAccountNumber(Account a, UserAccounts ua) {
-        synchronized(ua.cacheLock) {
-            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
-            int newAccountMapping = 0;
-            while(userAcctIdToAcctMap.get(newAccountMapping) != null) {
-                newAccountMapping++;
-            }
-            userAcctIdToAcctMap.put(newAccountMapping, a);
-            return newAccountMapping;
-        }
-    }
-
-
-
-    /**
-     * Registers an application, represented by a UID, to support account types detailed in
-     * the applications manifest as well as allowing it to opt for notifications.
+     * Registers an application, represented by a UID, to support account types detailed in the
+     * applications manifest as well as allowing it to opt for notifications.
      *
      * @param uid UID of application
      * @param ua UserAccount that currently hosts the account and application
@@ -834,105 +510,27 @@
         try {
             String[] allPackages = mPackageManager.getPackagesForUid(uid);
             if (allPackages != null) {
-                for(String aPackage : allPackages) {
+                for (String aPackage : allPackages) {
                     ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
                             PackageManager.GET_META_DATA);
                     Bundle b = ai.metaData;
-                    if(b == null) {
+                    if (b == null) {
                         return;
                     }
-                    interestedPackages = b.getString("android.accounts.SupportedLoginTypes");
+                    interestedPackages = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
                 }
             }
         } catch (PackageManager.NameNotFoundException e) {
             Log.d("NameNotFoundException", e.getMessage());
         }
-        if(interestedPackages != null) {
-            /* request remote account types directly from here. Reads from Android Manifest */
-            requestAccountVisibility(interestedPackages.split(";"), uid, ua);
+        if (interestedPackages != null) {
+            // TODO request visibility
+            // requestAccountVisibility(interestedPackages.split(";"), uid, ua);
         }
     }
 
     /**
-     * Allows AccountManager to register account types that an application has login
-     * support for. This method over-writes all of the application's previous settings
-     * for accounts it supported.
-     *
-     * @param accountTypes array of account types application wishes to support
-     * @param uid of application registering requested account types
-     * @param ua UserAccount that hosts the account and application
-     */
-    private void requestAccountVisibility(String[] accountTypes, int uid, UserAccounts ua) {
-        if(accountTypes.length > 0) {
-            clearRequestedAccountVisibility(uid, ua);
-            addRequestedAccountsVisibility(accountTypes, uid, ua);
-        }
-    }
-
-    /**
-     * Removes visibility of all Accounts to this particular UID. This is called when an
-     * application is uninstalled so another application that is installed with the same
-     * UID cannot access Accounts. This is called by AccountManager.
-     *
-     * @param uid of application to remove all Account visibility to
-     * @param ua UserAccount that hosts the current Account
-     */
-    private void removeAccountVisibilityAllAccounts(int uid, UserAccounts ua) {
-        synchronized(ua.cacheLock) {
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
-            ArrayList<Integer> allAccountNumbersList = userWlUidToMockAccountNums.get(uid);
-            if(allAccountNumbersList != null) {
-                Integer[] allAccountNumbers = allAccountNumbersList.toArray(
-                        new Integer[allAccountNumbersList.size()]);
-                for(int accountNum : allAccountNumbers) {
-                    removeAccountVisibility(userAcctIdToAcctMap.get(accountNum), uid, ua);
-                }
-            }
-        }
-    }
-
-    /**
-     * Removes visible list functionality of a certain Account.
-     * This method is currently called by (1) addAccountExplicitly (as opposed to
-     * addAccountExplicitlyWithUid) and (2) removeAccountExplicitly.
-     *
-     * @param a the account to clear the visible list functionality for
-     * @param ua currently UserAccounts profile containing Account
-     *
-     * @return true if account previously had visible list functionality
-     */
-    private boolean removeVisibleListFunctionality(Account a, UserAccounts ua) {
-        int mockAccountNum = getMockAccountNumber(a, ua);
-        if(mockAccountNum < 0) {
-            return false;
-        }
-        synchronized(ua.cacheLock) {
-            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
-                    ua.mVisibleListUidToMockAccountNumbers;
-            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
-
-            /* Removing mapping from account number to account removes visible list functionality*/
-            userAcctIdToAcctMap.remove(mockAccountNum);
-
-            for(int i = userWlUidToMockAccountNums.size() - 1 ; i >= 0  ; i--) {
-                int uidKey = userWlUidToMockAccountNums.keyAt(i);
-                ArrayList<Integer> allAccountNumbers = userWlUidToMockAccountNums.get(uidKey);
-                if(allAccountNumbers != null) {
-                    allAccountNumbers.remove(mockAccountNum);
-                    if(allAccountNumbers.isEmpty()) {
-                        userWlUidToMockAccountNums.remove(uidKey);
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Sends a direct intent to a package, notifying it of a visible account. This
-     * method is a helper method of makeAccountVisible.
+     * Sends a direct intent to a package, notifying it of a visible account change.
      *
      * @param desiredPackage to send Account to
      * @param visibleAccount to send to package
@@ -940,9 +538,10 @@
     private void sendNotification(String desiredPackage, Account visibleAccount) {
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
-        intent.setAction(NEW_ACCOUNT_VISIBLE);
+        intent.setAction(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
         intent.setPackage(desiredPackage);
-        intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
+        // TODO update documentation, add account extra if new account became visible
+        // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
         mContext.sendBroadcast(intent);
     }
 
@@ -1471,7 +1070,7 @@
                     account.type);
             throw new SecurityException(msg);
         }
-        removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
+
         /*
          * Child users are not allowed to add accounts. Only the accounts that are
          * shared by the parent profile can be added to child profile.
@@ -2050,7 +1649,6 @@
                     account.type);
             throw new SecurityException(msg);
         }
-        removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
         UserAccounts accounts = getUserAccountsForCaller();
         final long accountId = accounts.accountsDb.findDeAccountId(account);
         logRecord(
@@ -3303,7 +2901,7 @@
             throw new IllegalArgumentException("sessionBundle is empty");
         }
 
-        // Only allow the system process to finish session for other users
+        // Only allow the system process to finish session for other users.
         if (isCrossUser(callingUid, userId)) {
             throw new SecurityException(
                     String.format(
@@ -4095,23 +3693,11 @@
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            Account[] accountsToReturn = getAccountsInternal(
+            return getAccountsInternal(
                     accounts,
                     callingUid,
                     callingPackage,
                     visibleAccountTypes);
-            ArrayList<Account> accountsToReturnList = new
-                    ArrayList<Account>(Arrays.asList(accountsToReturn));
-            for(int i = accountsToReturnList.size() - 1; i >= 0 ; i--) {
-                // if account not visible to caller or managed by caller, remove from
-                // accounts to return. Note that all accounts visible by default unless
-                // visible list functionality implemented
-                if(!(isAccountVisible(accountsToReturnList.get(i), callingUid,
-                        getUserAccounts(userId)))) {
-                    accountsToReturnList.remove(i);
-                }
-            }
-            return accountsToReturnList.toArray(new Account[accountsToReturnList.size()]);
         } finally {
             restoreCallingIdentity(identityToken);
         }