1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
|
page.title=Creating a Stub Authenticator
trainingnavtop=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li>
<a href="#CreateAuthenticator">Add a Stub Authenticator Component</a>
</li>
<li>
<a href="#CreateAuthenticatorService">Bind the Authenticator to the Framework</a>
</li>
<li>
<a href="#CreateAuthenticatorFile">Add the Authenticator Metadata File</a>
</li>
<li>
<a href="#DeclareAuthenticator">Declare the Authenticator in the Manifest</a>
</li>
</ol>
<h2>You should also read</h2>
<ul>
<li>
<a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
</li>
</ul>
<h2>Try it out</h2>
<div class="download-box">
<a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
<p class="filename">BasicSyncAdapter.zip</p>
</div>
</div>
</div>
<p>
The sync adapter framework assumes that your sync adapter transfers data between device storage
associated with an account and server storage that requires login access. For this reason, the
framework expects you to provide a component called an authenticator as part of your sync
adapter. This component plugs into the Android accounts and authentication framework and
provides a standard interface for handling user credentials such as login information.
</p>
<p>
Even if your app doesn't use accounts, you still need to provide an authenticator component.
If you don't use accounts or server login, the information handled by the authenticator is
ignored, so you can provide an authenticator component that contains stub method
implementations. You also need to provide a bound {@link android.app.Service} that
allows the sync adapter framework to call the authenticator's methods.
</p>
<p>
This lesson shows you how to define all the parts of a stub authenticator that you need to
satisfy the requirements of the sync adapter framework. If you need to provide a real
authenticator that handles user accounts, read the reference documentation for
{@link android.accounts.AbstractAccountAuthenticator}.
</p>
<h2 id="CreateAuthenticator">Add a Stub Authenticator Component</h2>
<p>
To add a stub authenticator component to your app, create a class that extends
{@link android.accounts.AbstractAccountAuthenticator}, and then stub out the required methods,
either by returning {@code null} or by throwing an exception.
</p>
<p>
The following snippet shows an example of a stub authenticator class:
</p>
<pre>
/*
* Implement AbstractAccountAuthenticator and stub out all
* of its methods
*/
public class Authenticator extends AbstractAccountAuthenticator {
// Simple constructor
public Authenticator(Context context) {
super(context);
}
// Editing properties is not supported
@Override
public Bundle editProperties(
AccountAuthenticatorResponse r, String s) {
throw new UnsupportedOperationException();
}
// Don't add additional accounts
@Override
public Bundle addAccount(
AccountAuthenticatorResponse r,
String s,
String s2,
String[] strings,
Bundle bundle) throws NetworkErrorException {
return null;
}
// Ignore attempts to confirm credentials
@Override
public Bundle confirmCredentials(
AccountAuthenticatorResponse r,
Account account,
Bundle bundle) throws NetworkErrorException {
return null;
}
// Getting an authentication token is not supported
@Override
public Bundle getAuthToken(
AccountAuthenticatorResponse r,
Account account,
String s,
Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
// Getting a label for the auth token is not supported
@Override
public String getAuthTokenLabel(String s) {
throw new UnsupportedOperationException();
}
// Updating user credentials is not supported
@Override
public Bundle updateCredentials(
AccountAuthenticatorResponse r,
Account account,
String s, Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
// Checking features for the account is not supported
@Override
public Bundle hasFeatures(
AccountAuthenticatorResponse r,
Account account, String[] strings) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
}
</pre>
<h2 id="CreateAuthenticatorService">Bind the Authenticator to the Framework</h2>
<p>
In order for the sync adapter framework to access your authenticator, you must create a bound
Service for it. This service provides an Android binder object that allows the framework
to call your authenticator and pass data between the authenticator and the framework.
</p>
<p>
Since the framework starts this {@link android.app.Service} the first time it needs to
access the authenticator, you can also use the service to instantiate the authenticator,
by calling the authenticator constructor in the
{@link android.app.Service#onCreate Service.onCreate()} method of the service.
</p>
<p>
The following snippet shows you how to define the bound {@link android.app.Service}:
</p>
<pre>
/**
* A bound Service that instantiates the authenticator
* when started.
*/
public class AuthenticatorService extends Service {
...
// Instance field that stores the authenticator object
private Authenticator mAuthenticator;
@Override
public void onCreate() {
// Create a new authenticator object
mAuthenticator = new Authenticator(this);
}
/*
* When the system binds to this Service to make the RPC call
* return the authenticator's IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}
}
</pre>
<h2 id="CreateAuthenticatorFile">Add the Authenticator Metadata File</h2>
<p>
To plug your authenticator component into the sync adapter and account frameworks, you need to
provide these framework with metadata that describes the component. This metadata declares the
account type you've created for your sync adapter and declares user interface elements
that the system displays if you want to make your account type visible to the user. Declare this
metadata in a XML file stored in the {@code /res/xml/} directory in your app project.
You can give any name to the file, although it's usually called {@code authenticator.xml}.
</p>
<p>
This XML file contains a single element <code><account-authenticator></code> that
has the following attributes:
</p>
<dl>
<dt>
<code>android:accountType</code>
</dt>
<dd>
The sync adapter framework requires each sync adapter to have an account type, in the form
of a domain name. The framework uses the account type as part of the sync adapter's
internal identification. For servers that require login, the account type along with a
user account is sent to the server as part of the login credentials.
<p>
If your server doesn't require login, you still have to provide an account type. For the
value, use a domain name that you control. While the framework uses it to manage your
sync adapter, the value is not sent to your server.
</p>
</dd>
<dt>
<code>android:icon</code>
</dt>
<dd>
Pointer to a <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable</a>
resource containing an icon. If you make the sync adapter visible by specifying the
attribute <code>android:userVisible="true"</code> in <code>res/xml/syncadapter.xml</code>,
then you must provide this icon resource. It appears in the <b>Accounts</b> section of
the system's Settings app.
</dd>
<dt>
<code>android:smallIcon</code>
</dt>
<dd>
Pointer to a <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable</a>
resource containing a small version of the icon. This resource may be used instead of
<code>android:icon</code> in the <b>Accounts</b> section of the system's Settings app,
depending on the screen size.
</dd>
<dt>
<code>android:label</code>
</dt>
<dd>
Localizable string that identifies the account type to users. If you make the sync adapter
visible by specifying the attribute <code>android:userVisible="true"</code> in
<code>res/xml/syncadapter.xml</code>, then you should provide this string. It appears in the
<b>Accounts</b> section of the system's Settings app, next to the icon you define for the
authenticator.
</dd>
</dl>
<p>
The following snippet shows the XML file for the authenticator you created previously:
</p>
<pre>the
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="example.com"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:label="@string/app_name"/>
</pre>
<h2 id="DeclareAuthenticator">Declare the Authenticator in the Manifest</h2>
<p>
In a previous step, you created a bound {@link android.app.Service} that links the authenticator
to the sync adapter framework. To identify this service to the system, declare it in your app
manifest by adding the following
<code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code>
element as a child element of
<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>:
</p>
<pre>
<service
android:name="com.example.android.syncadapter.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
</pre>
<p>
The
<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code>
element sets up a filter that's triggered by the intent action
{@code android.accounts.AccountAuthenticator}, which sent by the system to run the
authenticator. When the filter is triggered, the system starts {@code AuthenticatorService},
the bound {@link android.app.Service} you have provided to wrap the authenticator.
</p>
<p>
The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
element declares the metadata for the authenticator. The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
attribute links the meta-data to the authentication framework. The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#rsrc">android:resource</a></code>
element specifies the name of the authenticator metadata file you created previously.
</p>
<p>
Besides an authenticator, a sync adapter also requires a content provider. If your app doesn't
use a content provider already, go to the next lesson to learn how to create a stub content
provider; otherwise, go to the lesson <a href="creating-sync-adapter.html"
>Creating a Sync Adapter</a>.
</p>
|