Revert "Permissions: Get rid of GET_ACCOUNTS"

This reverts commit 918c55a67c2bf0cec79f75dec6ca468e914a5fd1.

Change-Id: I995f134336bf61ac1f21052355900ae89d0d6694
diff --git a/api/current.txt b/api/current.txt
index 61ae1e0..14c7c0d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -68,7 +68,7 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
diff --git a/api/system-current.txt b/api/system-current.txt
index 321d817..f49a872 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -96,7 +96,7 @@
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
     field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
-    field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
diff --git a/api/test-current.txt b/api/test-current.txt
index ad45752..c6f791d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -68,7 +68,7 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 35695c4..1d9e3bb 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -430,46 +430,47 @@
     }
 
     /**
-     * List every {@link Account} registered on the device that are managed by
-     * applications whose signatures match the caller.
+     * Lists all accounts of any type registered on the device.
+     * Equivalent to getAccountsByType(null).
      *
-     * <p>This method can be called safely from the main thread. It is
-     * equivalent to calling <code>getAccountsByType(null)</code>.
+     * <p>It is safe to call this method from the main thread.
      *
-     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
-     * manifests will continue to behave as they did on devices that support
-     * API level 23. In particular the GET_ACCOUNTS permission is required to
-     * see all the Accounts registered with the AccountManager. See docs for
-     * this function in API level 23 for more information.
+     * <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 Array of Accounts. The array may be empty if no accounts are
-     *     available to the caller.
+     * @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() {
-        return getAccountsByType(null);
+        try {
+            return mService.getAccounts(null, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            // won't ever happen
+            throw new RuntimeException(e);
+        }
     }
 
     /**
      * @hide
-     * List every {@link Account} registered on the device for a specific User
-     * that are managed by applications whose signatures match the caller.
+     * Lists all accounts of any type registered on the device for a given
+     * user id. Equivalent to getAccountsByType(null).
      *
-     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
-     * manifests will continue to behave as they did on devices that support
-     * API level 23. In particular the GET_ACCOUNTS permission is required to
-     * see all the Accounts registered with the AccountManager for the
-     * specified userId. See docs for this function in API level 23 for more
-     * information.
+     * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method can be called safely 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.
      *
-     * @param int userId associated with the User whose accounts should be
-     *     queried.
-     * @return Array of Accounts. The array may be empty if no accounts are
-     *     available to the caller.
+     * @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());
@@ -500,11 +501,10 @@
     /**
      * Returns the accounts visible to the specified package, in an environment where some apps
      * are not authorized to view all accounts. This method can only be called by system apps.
-     *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @param packageName The package name of the app for which the accounts are to be returned
-     * @return Array of Accounts. The array may be empty if no accounts of th
-     *     specified type are visible to the caller.
+     * @return An array of {@link Account}, one per matching account.  Empty
+     *     (never null) if no accounts of the specified type have been added.
      */
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -518,22 +518,29 @@
     }
 
     /**
-     * List every {@link Account} of a specified type managed by applications
-     * whose signatures match the caller.
+     * 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.
      *
-     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
-     * manifests will continue to behave as they did on devices that support
-     * API level 23. See docs for this function in API level 23 for more
-     * information.
+     * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method can be called safely 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.
      *
-     * @param type String denoting the type of the accounts to return,
-     *        {@code null} to retrieve all accounts visible to the caller.
-     * @return An array of Accounts.  Empty (never null) if no accounts
-     *         are available to the caller.
+     * <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 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.
      */
     @NonNull
+    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsByType(String type) {
         return getAccountsByTypeAsUser(type, Process.myUserHandle());
     }
@@ -579,7 +586,6 @@
      * @return a future containing the label string
      * @hide
      */
-    @NonNull
     public AccountManagerFuture<String> getAuthTokenLabel(
             final String accountType, final String authTokenType,
             AccountManagerCallback<String> callback, Handler handler) {
@@ -612,13 +618,9 @@
      * <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>The specified account must be managed by an application
-     * whose signature matches the caller.
-     *
-     * <p><b>Further note:</b>Apps targeting API level 23 or earlier will continue to
-     * behave as they did on devices that support API level 23. In particular
-     * they may still require the GET_ACCOUNTS permission. See docs for this
-     * function in API level 23.
+     * <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.
      *
      * @param account The {@link Account} to test
      * @param features An array of the account features to check
@@ -627,11 +629,9 @@
      * @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.
-     * @throws SecurityException if the specified account is managed by an
-     *     application whose signature doesn't match the caller's signature.
+     * true if the account exists and has all of the specified features.
      */
-    @NonNull
+    @RequiresPermission(GET_ACCOUNTS)
     public AccountManagerFuture<Boolean> hasFeatures(final Account account,
             final String[] features,
             AccountManagerCallback<Boolean> callback, Handler handler) {
@@ -654,10 +654,9 @@
 
     /**
      * Lists all accounts of a type which have certain features.  The account
-     * type identifies the authenticator (see {@link #getAccountsByType}). Said
-     * authenticator must be in a package whose signature matches the callers
-     * package signature. Account features are authenticator-specific string tokens
-     * identifying boolean account properties (see {@link #hasFeatures}).
+     * 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,
@@ -666,14 +665,19 @@
      * <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> Apps targeting API level 23 or earlier will continue to
-     * behave as they did on devices that support API level 23. In particular
-     * they may still require the GET_ACCOUNTS permission. See docs for this
-     * function in API level 23.
+     * <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.
      *
      * @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,
@@ -682,7 +686,7 @@
      *     {@link Account}, one per account of the specified type which
      *     matches the requested features.
      */
-    @NonNull
+    @RequiresPermission(GET_ACCOUNTS)
     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
             final String type, final String[] features,
             AccountManagerCallback<Account[]> callback, Handler handler) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a518cc4..045ce5f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1209,8 +1209,7 @@
     <eat-comment />
 
     <!-- Allows access to the list of accounts in the Accounts Service.
-         <p>Protection level: dangerous
-         @deprecated Not operative for apps apps with targetSdkVersion >= 24.
+        <p>Protection level: normal
     -->
     <permission android:name="android.permission.GET_ACCOUNTS"
         android:permissionGroup="android.permission-group.CONTACTS"
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 8c392aa..cfd9467 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -160,21 +160,20 @@
         still perform BTLE and WiFi scans, but only when they are in the foreground. While in the background, those apps will get no results from BTLE and WiFi scans.</li>
     </ul>
   </li>
-  <li>Accessing accounts
+  <li>Permission changes
     <ul>
-      <li>Updated the behavior of {@link android.accounts.AccountManager} account
-        discovery methods.
+      <li>Updated the user interface for permissions and enhanced some of the permissions
+        behaviors.</li>
+      <li>The {@link android.Manifest.permission#GET_ACCOUNTS} permission is now a member of the
+        {@link android.Manifest.permission_group#CONTACTS} permission group and it has a
+        {@code android:protectionLevel} of {@code dangerous}. This change means that when
+        targeting Android 6.0 (API level 23), you must check for and request this permission if
+        your app requires it.
       </li>
-      <li>The GET_ACCOUNTS permission has been deprecated.
-      </li>
-      <li>Apps targeting API level 24 should start the intent returned by
-        newChooseAccountIntent(...) and await the result to acquire a reference
-        to the user's selected account. AccountManager methods like getAccounts and
-        related methods will only return those accounts managed by
-        authenticators that match the signatures of the calling app.
-      </li>
-      <li>Apps targeting API level 23 or earlier will continue to behave as
-        before.
+
+      <li>The {@code android.permission.READ_PROFILE} and {@code android.permission.WRITE_PROFILE}
+       permissions have been removed from the {@link android.Manifest.permission_group#CONTACTS}
+       permission group.
       </li>
     </ul>
   </li>
diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd
index 4c399f9..db9ab3a 100644
--- a/docs/html/training/id-auth/identify.jd
+++ b/docs/html/training/id-auth/identify.jd
@@ -15,7 +15,8 @@
 <ol>
   <li><a href="#ForYou">Determine if AccountManager is for You</a></li>
   <li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
-  <li><a href="#QueryAccounts">Query the user for an Account</a></li>
+  <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
+  <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
   <li><a href="#IdentifyUser">Use the Account Object to Personalize Your App</a></li>
   <li><a href="#IdIsEnough">Decide Whether an Account Name is Enough</a></li>
 </ol>
@@ -70,46 +71,48 @@
 <h2 id="TaskTwo">Decide What Type of Account to Use</h2>
 
 <p>Android devices can store multiple accounts from many different providers.
-When you query {@link android.accounts.AccountManager} for account names, you
-can choose to filter by account type. The account type is a string that
-uniquely identifies the entity that issued the account. For instance, Google
-accounts have type "com.google," while Twitter uses
-"com.twitter.android.auth.login."</p>
+When you query {@link android.accounts.AccountManager} for account names, you can choose to filter
+by
+account type. The account type is a string that uniquely identifies the entity
+that issued the account. For instance, Google accounts have type "com.google,"
+while Twitter uses "com.twitter.android.auth.login."</p>
 
-<h2 id="QueryAccounts">Query the user for an Account</h2>
 
-<p>Once an account type has been determined, you can prompt the user with an
-account chooser as follows:
+<h2 id="GetPermission">Request GET_ACCOUNT permission</h2>
+
+<p>In order to get a list of accounts on the device, your app needs the {@link
+android.Manifest.permission#GET_ACCOUNTS}
+permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
+<uses-permission>}</a> tag in your manifest file to request
+this permission:</p>
 
 <pre>
-AccountManager am = AccountManager.get(this);  // "this" reference the current Context
-Intent chooserIntent = am.newChooseAccountIntent(
-        null, // currently select account
-        null, // list of accounts that are allowed to be shown
-        new String[] { "com.google" }, // Only allow the user to select Google accounts
-        false,
-        null,  // description text
-        null, // add account auth token type
-        null, // required features for added accounts
-        null);  // options for adding an account
-this.startActivityForResult(chooserIntent, MY_REQUEST_CODE);
+&lt;manifest ... >
+    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
+    ...
+&lt;/manifest>
 </pre>
 
-<p>Once the chooser intent is started, the user will be presented with a list of
-appropriately typed accounts. From this list they will select one which will be
-returned to your app upon onActivityResult as follows:
+
+<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2>
+
+<p>Once you decide what account type you're interested in, you need to query for accounts of that
+type. Get an instance of {@link android.accounts.AccountManager} by calling {@link
+android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that
+instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String)
+getAccountsByType()}.</p>
 
 <pre>
-protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-    if (requestCode == MY_REQUEST_CODE && resultCode == RESULT_OK) {
-        String name = data.getStringExtra(AccountManage.KEY_ACCOUNT_NAME);
-        String type = data.getStringExtra(AccountManage.KEY_ACCOUNT_TYPE);
-        Account selectedAccount = new Account(name, type);
-        doSomethingWithSelectedAccount(selectedAccount);
-    }
-}
+AccountManager am = AccountManager.get(this); // "this" references the current Context
+
+Account[] accounts = am.getAccountsByType("com.google");
 </pre>
 
+<p>This returns an array of {@link android.accounts.Account} objects. If there's more than one
+{@link android.accounts.Account} in
+the array, you should present a dialog asking the user to select one.</p>
+
+
 <h2 id="IdentifyUser">Use the Account Object to Personalize Your App</h2>
 
 <p>The {@link android.accounts.Account} object contains an account name, which for Google accounts
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 143015f..2683be6 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4266,6 +4266,21 @@
         }
     }
 
+    private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
+        for (String perm : permissions) {
+            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
+                }
+                final int opCode = AppOpsManager.permissionToOpCode(perm);
+                if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+                        opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 
     private int handleIncomingUser(int userId) {
         try {
@@ -4340,53 +4355,12 @@
 
     private List<String> getTypesVisibleToCaller(int callingUid, int userId,
             String opPackageName) {
-        List<String> permissionsToCheck = new ArrayList<String>(2);
-        permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
-        long id = Binder.clearCallingIdentity();
-        try {
-            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
-                    opPackageName, 0 /* flags */);
-            /*
-             * At or before SDK 23, clients discover all the accounts in their
-             * user profile (via AccountManager.getAccounts(...)) by declaring
-             * the GET_ACCOUNTS permission.
-             *
-             * After SDK 23 the GET_ACCOUNTS permission is deprecated.  Instead
-             * apps will be able to retrieve those accounts managed by
-             * authenticators sharing a package signature without any special
-             * permissions. The only clients able to discover all the accounts
-             * on the device will be those with the GET_ACCOUNTS_PRVILEGED
-             * system permission.
-             */
-            if (23 >= appInfo.targetSdkVersion) {
-                permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS);
-            }
-        } catch (NameNotFoundException e) {
-            // No application associated with the specified package.
-            Log.w(TAG, "No application associated with package: " + opPackageName);
-        } finally {
-            Binder.restoreCallingIdentity(id);
-        }
-        boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck);
+        boolean isPermitted =
+                isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
+                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
         return getTypesForCaller(callingUid, userId, isPermitted);
     }
 
-    private boolean isPermitted(String opPackageName, int callingUid, List<String> permissions) {
-        for (String perm : permissions) {
-            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
-                }
-                final int opCode = AppOpsManager.permissionToOpCode(perm);
-                if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
-                        opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private List<String> getTypesManagedByCaller(int callingUid, int userId) {
         return getTypesForCaller(callingUid, userId, false);
     }