AbstractAccountAuthenticator.java revision ffd0cb04f97e62d286d185c520580d81a9c328b1
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.accounts; 18 19import android.os.Bundle; 20import android.os.RemoteException; 21import android.os.Binder; 22import android.util.Log; 23import android.content.pm.PackageManager; 24import android.content.Context; 25import android.Manifest; 26 27/** 28 * Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator 29 * binder interface and also provides helper libraries to simplify the creation of 30 * AccountAuthenticators. 31 */ 32public abstract class AbstractAccountAuthenticator { 33 private final Context mContext; 34 35 public AbstractAccountAuthenticator(Context context) { 36 mContext = context; 37 } 38 39 class Transport extends IAccountAuthenticator.Stub { 40 public void addAccount(IAccountAuthenticatorResponse response, String accountType, 41 String authTokenType, String[] requiredFeatures, Bundle options) 42 throws RemoteException { 43 checkBinderPermission(); 44 final Bundle result; 45 try { 46 result = AbstractAccountAuthenticator.this.addAccount( 47 new AccountAuthenticatorResponse(response), 48 accountType, authTokenType, requiredFeatures, options); 49 } catch (NetworkErrorException e) { 50 response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); 51 return; 52 } catch (UnsupportedOperationException e) { 53 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 54 "addAccount not supported"); 55 return; 56 } 57 if (result != null) { 58 response.onResult(result); 59 } 60 } 61 62 public void confirmPassword(IAccountAuthenticatorResponse response, 63 Account account, String password) throws RemoteException { 64 checkBinderPermission(); 65 boolean result; 66 try { 67 result = AbstractAccountAuthenticator.this.confirmPassword( 68 new AccountAuthenticatorResponse(response), 69 account, password); 70 } catch (UnsupportedOperationException e) { 71 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 72 "confirmPassword not supported"); 73 return; 74 } catch (NetworkErrorException e) { 75 response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); 76 return; 77 } 78 Bundle bundle = new Bundle(); 79 bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result); 80 response.onResult(bundle); 81 } 82 83 public void confirmCredentials(IAccountAuthenticatorResponse response, 84 Account account) throws RemoteException { 85 checkBinderPermission(); 86 final Bundle result; 87 try { 88 result = AbstractAccountAuthenticator.this.confirmCredentials( 89 new AccountAuthenticatorResponse(response), account); 90 } catch (UnsupportedOperationException e) { 91 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 92 "confirmCredentials not supported"); 93 return; 94 } 95 if (result != null) { 96 response.onResult(result); 97 } 98 } 99 100 public void getAuthTokenLabel(IAccountAuthenticatorResponse response, 101 String authTokenType) 102 throws RemoteException { 103 checkBinderPermission(); 104 try { 105 Bundle result = new Bundle(); 106 result.putString(Constants.AUTH_TOKEN_LABEL_KEY, 107 AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType)); 108 response.onResult(result); 109 } catch (IllegalArgumentException e) { 110 response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, 111 "unknown authTokenType"); 112 } catch (UnsupportedOperationException e) { 113 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 114 "getAuthTokenTypeLabel not supported"); 115 } 116 } 117 118 public void getAuthToken(IAccountAuthenticatorResponse response, 119 Account account, String authTokenType, Bundle loginOptions) 120 throws RemoteException { 121 checkBinderPermission(); 122 try { 123 final Bundle result = AbstractAccountAuthenticator.this.getAuthToken( 124 new AccountAuthenticatorResponse(response), account, 125 authTokenType, loginOptions); 126 if (result != null) { 127 response.onResult(result); 128 } 129 } catch (UnsupportedOperationException e) { 130 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 131 "getAuthToken not supported"); 132 } catch (NetworkErrorException e) { 133 response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); 134 } 135 } 136 137 public void updateCredentials(IAccountAuthenticatorResponse response, Account account, 138 String authTokenType, Bundle loginOptions) throws RemoteException { 139 checkBinderPermission(); 140 final Bundle result; 141 try { 142 result = AbstractAccountAuthenticator.this.updateCredentials( 143 new AccountAuthenticatorResponse(response), account, 144 authTokenType, loginOptions); 145 } catch (UnsupportedOperationException e) { 146 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 147 "updateCredentials not supported"); 148 return; 149 } 150 if (result != null) { 151 response.onResult(result); 152 } 153 } 154 155 public void editProperties(IAccountAuthenticatorResponse response, 156 String accountType) throws RemoteException { 157 checkBinderPermission(); 158 final Bundle result; 159 try { 160 result = AbstractAccountAuthenticator.this.editProperties( 161 new AccountAuthenticatorResponse(response), accountType); 162 } catch (UnsupportedOperationException e) { 163 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 164 "editProperties not supported"); 165 return; 166 } 167 if (result != null) { 168 response.onResult(result); 169 } 170 } 171 172 public void hasFeatures(IAccountAuthenticatorResponse response, 173 Account account, String[] features) throws RemoteException { 174 checkBinderPermission(); 175 final Bundle result; 176 try { 177 result = AbstractAccountAuthenticator.this.hasFeatures( 178 new AccountAuthenticatorResponse(response), account, features); 179 } catch (UnsupportedOperationException e) { 180 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 181 "hasFeatures not supported"); 182 return; 183 } catch (NetworkErrorException e) { 184 response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); 185 return; 186 } 187 if (result != null) { 188 response.onResult(result); 189 } 190 } 191 192 public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response, 193 Account account) throws RemoteException { 194 checkBinderPermission(); 195 try { 196 final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed( 197 new AccountAuthenticatorResponse(response), account); 198 if (result != null) { 199 response.onResult(result); 200 } 201 } catch (UnsupportedOperationException e) { 202 response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, 203 "getAccountRemovalAllowed not supported"); 204 return; 205 } catch (NetworkErrorException e) { 206 response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); 207 return; 208 } 209 } 210 } 211 212 private void checkBinderPermission() { 213 final int uid = Binder.getCallingUid(); 214 final String perm = Manifest.permission.ACCOUNT_MANAGER_SERVICE; 215 if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 216 throw new SecurityException("caller uid " + uid + " lacks " + perm); 217 } 218 } 219 220 Transport mTransport = new Transport(); 221 222 /** 223 * @return the IAccountAuthenticator binder transport object 224 */ 225 public final IAccountAuthenticator getIAccountAuthenticator() 226 { 227 return mTransport; 228 } 229 230 /** 231 * Returns a Bundle that contains the Intent of the activity that can be used to edit the 232 * properties. In order to indicate success the activity should call response.setResult() 233 * with a non-null Bundle. 234 * @param response used to set the result for the request. If the Constants.INTENT_KEY 235 * is set in the bundle then this response field is to be used for sending future 236 * results if and when the Intent is started. 237 * @param accountType the AccountType whose properties are to be edited. 238 * @return a Bundle containing the result or the Intent to start to continue the request. 239 * If this is null then the request is considered to still be active and the result should 240 * sent later using response. 241 */ 242 public abstract Bundle editProperties(AccountAuthenticatorResponse response, 243 String accountType); 244 public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType, 245 String authTokenType, String[] requiredFeatures, Bundle options) 246 throws NetworkErrorException; 247 /* @deprecated */ 248 public abstract boolean confirmPassword(AccountAuthenticatorResponse response, 249 Account account, String password) throws NetworkErrorException; 250 public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response, 251 Account account); 252 public abstract Bundle getAuthToken(AccountAuthenticatorResponse response, 253 Account account, String authTokenType, Bundle loginOptions) 254 throws NetworkErrorException; 255 public abstract String getAuthTokenLabel(String authTokenType); 256 public abstract Bundle updateCredentials(AccountAuthenticatorResponse response, 257 Account account, String authTokenType, Bundle loginOptions); 258 public abstract Bundle hasFeatures(AccountAuthenticatorResponse response, 259 Account account, String[] features) throws NetworkErrorException; 260 public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, 261 Account account) throws NetworkErrorException { 262 final Bundle result = new Bundle(); 263 result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true); 264 return result; 265 } 266} 267