diff --git a/api/current.txt b/api/current.txt index 21e66bd519042..a90192c719388 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16987,6 +16987,7 @@ package android.os { } public class UserManager { + method public static synchronized android.os.UserManager get(android.content.Context); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); method public android.os.UserHandle getUserForSerialNumber(long); diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index bdc882ac7fe65..241a64af65ae1 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -387,6 +387,23 @@ public class AccountManager { } } + /** + * @hide + * For use by internal activities. Returns the list of accounts that the calling package + * is authorized to use, particularly for shared accounts. + * @param packageName package name of the calling app. + * @param uid the uid of the calling app. + * @return the accounts that are available to this package and user. + */ + public Account[] getAccountsForPackage(String packageName, int uid) { + try { + return mService.getAccountsForPackage(packageName, uid); + } catch (RemoteException re) { + // possible security exception + throw new RuntimeException(re); + } + } + /** * Lists all accounts of a particular type. The account type is a * string token corresponding to the authenticator and useful domain @@ -575,7 +592,7 @@ public class AccountManager { public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) throw new IllegalArgumentException("account is null"); try { - return mService.addAccount(account, password, userdata); + return mService.addAccountExplicitly(account, password, userdata); } catch (RemoteException e) { // won't ever happen throw new RuntimeException(e); @@ -1123,7 +1140,7 @@ public class AccountManager { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { - mService.addAcount(mResponse, accountType, authTokenType, + mService.addAccount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start(); diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index 5358bc796ab94..2aba16339a34b 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -18,9 +18,14 @@ package android.accounts; import com.google.android.collect.Sets; import android.app.Activity; +import android.app.ActivityManagerNative; import android.content.Intent; import android.os.Bundle; +import android.os.IBinder; import android.os.Parcelable; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -29,6 +34,7 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.R; @@ -119,6 +125,9 @@ public class ChooseTypeAndAccountActivity extends Activity private Parcelable[] mExistingAccounts = null; private int mSelectedItemIndex; private Button mOkButton; + private int mCallingUid; + private String mCallingPackage; + private boolean mDisallowAddAccounts; @Override public void onCreate(Bundle savedInstanceState) { @@ -128,6 +137,24 @@ public class ChooseTypeAndAccountActivity extends Activity + savedInstanceState + ")"); } + String message = null; + + try { + IBinder activityToken = getActivityToken(); + mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken); + mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage( + activityToken); + if (mCallingUid != 0 && mCallingPackage != null) { + Bundle restrictions = UserManager.get(this) + .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid))); + mDisallowAddAccounts = + restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false); + } + } catch (RemoteException re) { + // Couldn't figure out caller details + Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re); + } + // save some items we use frequently final Intent intent = getIntent(); @@ -179,6 +206,11 @@ public class ChooseTypeAndAccountActivity extends Activity // If there are no relevant accounts and only one relevant account type go directly to // add account. Otherwise let the user choose. if (mAccounts.isEmpty()) { + if (mDisallowAddAccounts) { + setContentView(R.layout.app_not_authorized); + setTitle(R.string.error_message_title); + return; + } if (mSetOfRelevantAccountTypes.size() == 1) { runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next()); } else { @@ -296,7 +328,8 @@ public class ChooseTypeAndAccountActivity extends Activity } if (accountName == null || accountType == null) { - Account[] currentAccounts = AccountManager.get(this).getAccounts(); + Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage( + mCallingPackage, mCallingUid); Set preExistingAccounts = new HashSet(); for (Parcelable accountParcel : mExistingAccounts) { preExistingAccounts.add((Account) accountParcel); @@ -347,7 +380,8 @@ public class ChooseTypeAndAccountActivity extends Activity AccountManager.KEY_INTENT); if (intent != null) { mPendingRequest = REQUEST_ADD_ACCOUNT; - mExistingAccounts = AccountManager.get(this).getAccounts(); + mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage, + mCallingUid); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(intent, REQUEST_ADD_ACCOUNT); return; @@ -424,12 +458,14 @@ public class ChooseTypeAndAccountActivity extends Activity private String[] getListOfDisplayableOptions(ArrayList accounts) { // List of options includes all accounts found together with "Add new account" as the // last item in the list. - String[] listItems = new String[accounts.size() + 1]; + String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)]; for (int i = 0; i < accounts.size(); i++) { listItems[i] = accounts.get(i).name; } - listItems[accounts.size()] = getResources().getString( - R.string.add_account_button_label); + if (!mDisallowAddAccounts) { + listItems[accounts.size()] = getResources().getString( + R.string.add_account_button_label); + } return listItems; } @@ -439,7 +475,8 @@ public class ChooseTypeAndAccountActivity extends Activity * allowable accounts, if provided. */ private ArrayList getAcceptableAccountChoices(AccountManager accountManager) { - final Account[] accounts = accountManager.getAccounts(); + final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage, + mCallingUid); ArrayList accountsToPopulate = new ArrayList(accounts.length); for (Account account : accounts) { if (mSetOfAllowableAccounts != null diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 47b257d7241a3..81418132d5c8b 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -31,10 +31,11 @@ interface IAccountManager { String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(); Account[] getAccounts(String accountType); + Account[] getAccountsForPackage(String packageName, int uid); Account[] getAccountsAsUser(String accountType, int userId); void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features); void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features); - boolean addAccount(in Account account, String password, in Bundle extras); + boolean addAccountExplicitly(in Account account, String password, in Bundle extras); void removeAccount(in IAccountManagerResponse response, in Account account); void invalidateAuthToken(String accountType, String authToken); String peekAuthToken(in Account account, String authTokenType); @@ -47,7 +48,7 @@ interface IAccountManager { void getAuthToken(in IAccountManagerResponse response, in Account account, String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch, in Bundle options); - void addAcount(in IAccountManagerResponse response, String accountType, + void addAccount(in IAccountManagerResponse response, String accountType, String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch, in Bundle options); void updateCredentials(in IAccountManagerResponse response, in Account account, diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1ba16bd1430df..b9b8f083ba1a3 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -121,6 +121,14 @@ public class UserManager { */ public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; + private static UserManager sInstance = null; + + public synchronized static UserManager get(Context context) { + if (sInstance == null) { + sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE); + } + return sInstance; + } /** @hide */ public UserManager(Context context, IUserManager service) { diff --git a/core/res/res/layout/app_not_authorized.xml b/core/res/res/layout/app_not_authorized.xml new file mode 100644 index 0000000000000..bd40eeb0b31d6 --- /dev/null +++ b/core/res/res/layout/app_not_authorized.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + +