diff options
| -rw-r--r-- | core/java/android/app/backup/BackupAgent.java | 7 | ||||
| -rw-r--r-- | core/java/android/app/backup/package.html | 27 | ||||
| -rw-r--r-- | docs/html/guide/appendix/market-filters.jd | 83 | ||||
| -rw-r--r-- | docs/html/guide/guide_toc.cs | 15 | ||||
| -rw-r--r-- | docs/html/guide/practices/compatibility.jd | 242 | ||||
| -rw-r--r-- | docs/html/guide/topics/data/backup.jd | 761 | ||||
| -rw-r--r-- | docs/html/sdk/ndk/index.jd | 7 |
7 files changed, 1089 insertions, 53 deletions
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 5245da5023d9..cb4e0e784003 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -162,9 +162,10 @@ public abstract class BackupAgent extends ContextWrapper { * file descriptor pointing to a full snapshot of the * application's data. The application should consume every * entity represented in this data stream. - * @param appVersionCode The - * {@link android.R.styleable#AndroidManifest_versionCode android:versionCode} - * value of the application that backed up this particular data set. This + * @param appVersionCode The value of the <a + * href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code + * android:versionCode}</a> manifest attribute, + * from the application that backed up this particular data set. This * makes it possible for an application's agent to distinguish among any * possible older data versions when asked to perform the restore * operation. diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html index e2518ec56c5b..ae29994ab5a9 100644 --- a/core/java/android/app/backup/package.html +++ b/core/java/android/app/backup/package.html @@ -2,23 +2,28 @@ <BODY> <p>Contains the backup and restore functionality available to applications. If a user wipes the data on their device or upgrades to a new Android-powered -device, all applications that have enabled backup will restore the user's previous data and/or -preferences. {@more} All backup management is controlled through -{@link android.app.backup.BackupManager}. Individual backup functionality is -implemented through a subclass {@link android.app.backup.BackupAgent} and a -simple and easy-to-use implementation is provided in -{@link android.app.backup.BackupAgentHelper}.</p> +device, all applications that have enabled backup will restore the user's previous data.</p> +{@more} -<p>STOPSHIP: add more documentation and remove Dev Guide link if not written!</p> +<p>All backup and restore operations are controlled by the {@link +android.app.backup.BackupManager}. Each application that would +like to enable backup and preserve its data on remote strage must implement a +backup agent. A backup agent can be built by extending either {@link android.app.backup.BackupAgent} +or {@link android.app.backup.BackupAgentHelper}. The {@link +android.app.backup.BackupAgentHelper} class provides a wrapper around {@link +android.app.backup.BackupAgent} that simplifies the procedures to implement a backup agent by +employing backup helpers such as {@link android.app.backup.SharedPreferencesBackupHelper} and +{@link android.app.backup.FileBackupHelper}.</p> <p>The backup APIs let applications:</p> <ul> - <li>Perform backup of arbitrary data</li> - <li>Easily perform backup of Preferences and files</li> - <li>Handle restore of data</li> + <li>Perform backup of arbitrary data to remote storage</li> + <li>Easily perform backup of {@link android.content.SharedPreferences} and files</li> + <li>Restore the data saved to remote storage</li> </ul> <p>For a detailed guide to using the backup APIs, see the <a -href="{@docRoot}guide/topics/backup.html">Backup Dev Guide topic</a>.</p> +href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p> + </BODY> </HTML> diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd index 201a14202ccc..0797892ac5b6 100644 --- a/docs/html/guide/appendix/market-filters.jd +++ b/docs/html/guide/appendix/market-filters.jd @@ -4,25 +4,24 @@ page.title=Market Filters <div id="qv-wrapper">
<div id="qv">
-<h2 align="left">Market Filters quickview</h2>
-<ul> <li>Android Market applies filters to control which apps are visible to a
-user.</li> <li>Filtering is determined by elements in an app's manifest file,
+<h2 align="left">Market filters quickview</h2>
+<ul> <li>Android Market applies filters to that let you control whether your app is shown to a
+user who is browing or searching for apps.</li>
+<li>Filtering is determined by elements in an app's manifest file,
aspects of the device being used, and other factors.</li> </ul>
<h2>In this document</h2>
<ol> <li><a href="#how-filters-work">How Filters Work in Android Market</a></li>
-<li><a href="#manifest-filters">The Manifest File</a>
- <ol>
- <li><a href="#affects-filtering">Elements that affect filtering</a></li>
- </ol>
-</li>
+<li><a href="#manifest-filters">Filtering based on Manifest File Elements</a></li>
<li><a href="#other-filters">Other Filters</a></li>
</ol>
<h2>See also</h2>
<ol>
-<li><code><a
+<li><a
+href="{@docRoot}guide/practices/compatibility.html">Compatibility</a></li>
+<li style="margin-top:2px;"><code><a
href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code></li>
<li><code><a
href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code></li>
@@ -55,18 +54,29 @@ of a SIM card, and other factors. </p> <p>Changes to the Android Market filters are independent of changes
to the Android platform itself. This document will be updated periodically to reflect
-any changes that might occur. </p>
+any changes that occur. </p>
<h2 id="how-filters-work">How Filters Work in Android Market</h2>
-<p>If any one of the filter restrictions described in the following sections applies to
-an application, then the application will not appear in search results or category
-browsing on Android Market. </p><p> You can request any combination of the available filters for your
-app — for example, you could set a <code>minSdkVersion</code> of 4 and set
-<code>smallScreens</code> to false in the app, then when uploading the app to
+<p>Android Market uses the filter restrictions described below to determine
+whether to show your application to a user who is browsing or searching for
+applications on a given device. When determining whether to display your app,
+Market checks the device's hardware and software capabilities, as well as it's
+carrier, location, and other characteristics. It then compares those against the
+restrictions and dependencies expressed by the application itself, in its
+manifest, <code>.apk</code>, and publishing details. If the application is
+compatible with the device according to the filter rules, Market displays the
+application to the user. Otherwise, Market hides your application from search
+results and category browsing. </p>
+
+<p> You can use the filters described below to control whether Market shows or
+hides your application to users. You can request any combination of the
+available filters for your app — for example, you could set a
+<code>minSdkVersion</code> requirement of <code>"4"</code> and set
+<code>smallScreens="false"</code> in the app, then when uploading the app to
Market you could target European countries (carriers) only. Android Market's
-filters would prevent the application from being visible on any device that did not
-match all three of these requirements. </p>
+filters would prevent the application from being visible on any device that did
+not match all three of these requirements. </p>
<p>A filtered app is not visible within Market, even if a user specifically requests
the app by clicking a deep link that points directly to the app's ID within Market.
@@ -74,22 +84,26 @@ All filtering restrictions are associated with an application's version and can change between versions. For example:</p>
<ul>
-<li>If you publish a new version of
-your app with stricter restrictions, the app will not be visible to users for whom
-it is filtered, even if those users were able see the previous version.</li> <li>If
-a user has installed your application and you publish an upgrade that makes the app
-invisible to the user, the user will not see that an upgrade is available.
-</li>
+<li>If you publish a new version of your app with stricter restrictions, the app
+will not be visible to users for whom it is filtered, even if those users were
+able see the previous version.</li>
+<li>If a user has installed your application and you publish an upgrade that
+makes the app invisible to the user, the user will not see that an upgrade is
+available. </li>
</ul>
-<h2 id="manifest-filters">The Manifest File</h2>
-<p>Most Market filters are triggered by elements within an application's manifest file, <a
-href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>,
-although not everything in the manifest file can trigger filtering. </p>
-<h3 id="affects-filtering">Elements that affect filtering</h3>
-<p>The following table lists the manifest elements that can be used to trigger
-Android Market filtering, and explains how they work.</p>
-<table border="1">
+<h2 id="manifest-filters">Filtering based on Manifest Elements</h2>
+
+<p>Most Market filters are triggered by elements within an application's
+manifest file, <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>,
+although not everything in the manifest file can trigger filtering. The
+table below lists the manifest elements that you can use to trigger Android
+Market filtering, and explains how the filtering works.</p>
+
+<p class="table-caption"><strong>Table 1.</strong> Manifest elements that
+trigger filtering on Market.</p>
+<table>
<tr>
<th>Manifest Element</th>
<th>Filter Name</th>
@@ -199,7 +213,7 @@ href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><code>< <p><em>A note about camera:</em> If an
application requests the CAMERA permission using the <a
href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> <code><uses-permission></code></a> element, Market assumes that the
- application requires the camera and autofocus features. For applications that require the camera and are designed to run on Android 1.5 (API Level 3), declaring the CAMERA permission is an effective way of ensuring that Market filters your app properly, since <code>uses-feature</code> filtering is not available to applications compiled against the Android 1.5 platform. For more details about requiring or requesting a camera, see the <a href="{@docRoot}guide/topics/manifest/uses-library-element.html#required"> <code>required</code></a> attribute of <code><uses-feature></code>. </p></td>
+ application requires the camera and all camera features (such as autofocus). For applications that require the camera and are designed to run on Android 1.5 (API Level 3), declaring the CAMERA permission is an effective way of ensuring that Market filters your app properly, since <code>uses-feature</code> filtering is not available to applications compiled against the Android 1.5 platform. For more details about requiring or requesting a camera, see the <a href="{@docRoot}guide/topics/manifest/uses-library-element.html#required"> <code>required</code></a> attribute of <code><uses-feature></code>. </p></td>
</tr>
<tr>
<td valign="top">OpenGL-ES
@@ -269,9 +283,10 @@ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#max"><code>android:m </table>
<h2 id="other-filters">Other Filters</h2>
-<p>The following table describes other application characteristics that trigger Android Market filtering. </p>
+<p>Android Market uses other application characteristics to determine whether to show or hide an application for a particular user on a given device, as described in the table below. </p>
-<table border="1"> <tr>
+<p class="table-caption"><strong>Table 2.</strong> Application and publishing characteristics that affect filtering on Market.</p>
+<table> <tr>
<th>Filter Name</th> <th>How It Works</th> </tr>
<tr>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 3d356ae1db1a..19f0f1df950b 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -144,9 +144,17 @@ <li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html"> <span class="en">Intents and Intent Filters</span> </a></li> - <li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html"> + <li class="toggle-list"> + <div><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html"> <span class="en">Data Storage</span> - </a></li> + </a> <span class="new">new!</span></div> + <ul> + <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html"> + <span class="en">Data Backup</span> + </a> <span class="new">new!</span> + </li> + </ul> + </li> <li><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html"> <span class="en">Content Providers</span> </a></li> @@ -390,6 +398,9 @@ <span class="zh-TW" style="display:none">最佳實務</span> </h2> <ul> + <li><a href="<?cs var:toroot ?>guide/practices/compatibility.html"> + <span class="en">Compatibility</span> + </a><span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>guide/practices/screens_support.html"> <span class="en">Supporting Multiple Screens</span> </a></li> diff --git a/docs/html/guide/practices/compatibility.jd b/docs/html/guide/practices/compatibility.jd new file mode 100644 index 000000000000..d198166588c8 --- /dev/null +++ b/docs/html/guide/practices/compatibility.jd @@ -0,0 +1,242 @@ +page.title=Android Compatibility +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>See also</h2> + <ol> +<li><a +href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a></li> +<li><a +href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing Alternative Resources</a></li> +<li><a +href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li> +<li style="margin-top:3px;"><code><a +href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code></li> +<li><code><a +href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code></li> +<li><code><a +href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a></code></li> +<li><code><a +href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code></li> +<li><code><a +href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code></li> +<li><code><a +href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk></code></a></li> +</ol> + + +</div> </div> + +<p>Android is designed to run on many different types of devices. For +developers, the range and number of devices means a huge potential audience: the +more devices that run Android apps, the more users who can access your app. In +exchange, however, it also means that your apps will have to cope with that same +variety of hardware.</p> + +<p>Fortunately, Android has built-in tools and support that make it easy for +your apps to do that, while at the same time maintaining control of what types +of devices your app is available to. If you do your work properly, users +whose devices can’t run your app will never see it in the Android Market, and +will not get in trouble by downloading it. This page explains how you can +control which devices have access to your apps, and how to prepare your apps to +make sure they reach the right audience.</p> + + +<h3 id="defined">What does “Compatibility” mean?</h3> + +<p>A device is “Android compatible” if it can run apps written for the +<em>Android execution environment</em>. The exact details of the Android +execution environment are defined by the Android Compatibility Definition +Document, but the single most to the ability to install and correctly run an +Android <code>.apk</code> file.</p> + +<p>There is exactly one Android API for each <a +href="{@docRoot}guide/appendix/api-levels.html">API level</a>, and it’s the same +API no matter what kind of device it’s installed on. No parts of the API are +optional, and you never have to worry about parts of the API missing on some +devices. Every compatible Android device your app will land on will include +every class and every API for that API level.</p> + +<p>Of course, some APIs won’t work correctly if a particular device lacks the +corresponding hardware or feature. But that’s not a problem: we also designed +Android to prevent apps from being visible to devices which don’t have features +the apps require. We’ve built support for this right into the SDK tools, and +it’s part of the Android platform itself, as well as Android Market.</p> + +<p>As a developer, you have complete control of how and where your apps are +available. Android provides tools as a first-class part of the platform that let +you manage this. You control the availability of your apps, so that they reach +only the devices capable of running them.</p> + +<h3 id="how">How does it work?</h3> + +<p>You manage your app’s availability through a simple three-step process:</p> + +<ol> +<li>You state the features your app requires by declaring <a +href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a> +elements its manifest file.</li> +<li>Devices are required to declare the features they include to Android +Market.</li> +<li>Android Market uses your app’s stated requirements to filter it from devices +that don’t meet those requirements.</li> +</ol> + +<p>This way, users never even see apps that won’t work properly on their +devices. As long as you accurately describe your app’s requirements, you don’t +need to worry about users blaming you for compatibility problems.</p> + +<p>If you’re familiar with web development, you may recognize this model as +“capability detection”. Web developers typically prefer this approach to +“browser detection”, because it’s very difficult to keep up as new browsers and +new versions of current browsers are released. By checking for support for +specific required capabilities instead of the current browser, web developers +get better fine-grained control. That’s the same approach Android uses: since +it’s impossible to keep up with all the Android devices being released, you +instead use the fine-grained controls Android provides.</p> + +<h3>Filtering for technical reasons</h3> + + <div class="sidebox-wrapper"> + <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png"> + <div id="qv-sub-rule"> + <img src="{@docRoot}assets/images/icon_market.jpg" style="float:left;margin:0;padding:0;"> + <p style="color:#669999;">Filtering on Android Market</p> + + <p>Android Market filters the applications that are visible to users, so +that users can see and download only those applications that are compatible with +their devices.</p> + + <p style="margin-top:1em;">One of the ways Market filters applications is by +feature compatibility. To do this, Market checks the +<code><uses-feature></code> elements in each application's manifest, to +establish the app's feature needs. Market then shows or hides the application to +each user, based on a comparison with the features available on the user's +device. + +<p style="margin-top:1em;">For information about other filters that you can +use to control the availability of your apps, see the +<a href="{@docRoot}guide/appendix/market-filters.html">Market +Filters</a> document.</p> + </div> +</div> + +<p>Android includes support for a lot of features, some hardware and some +software. Examples include compass and accelerometer sensors, cameras, and Live +Wallpapers. However, not every device will support every feature. For instance, +some devices don’t have the hardware horsepower to display Live Wallpapers +well.</p> + +<p>To manage this, Android defines <em>feature IDs</em>. Every capability has a +corresponding feature ID defined by the Android platform. For instance, the +feature ID for compass is <code>“android.hardware.sensor.compass”</code>, +while the feature +ID for Live Wallpapers is <code>“android.software.live_wallpapers”</code>. Each of these IDs +also has a corresponding Java-language constant on the +{@link android.content.pm.PackageManager} class that you can use to query whether +feature is supported at runtime. As Android adds support for new features in +future versions, new feature IDs will be added as well.</p> + +<p>When you write your application, you specify which features your app requires +by listing their feature IDs in <code><uses-feature></code> elements in +the <code>AndroidManifest.xml</code> file. This is the information that Android +Market uses to match your app to devices that can run it. For instance, if you +state that your app requires android.software.live_wallpapers, it won’t be shown +to devices that don’t support Live Wallpapers.</p> + +<p>This puts you in total control of your app — because you don’t have to +declare these features. Consider an example involving cameras.</p> + +<p>If you’re building a really impressive next-generation augmented-reality app, +your app won’t function at all without a camera. However, if you’re building a +shopping app that only uses the camera for barcode scanning, users without +cameras might still find it useful even if they can’t scan barcodes. While both +apps need to acquire the permission to access the camera, only the first app +needs to state that it requires a camera. (The shopping app can simply check at +runtime and disable the camera-related features if there’s no camera +present.)</p> + +<p>Since only you can say what the best approach is for your app, Android +provides the tools and lets you make your own tradeoff between maximizing +audience size and minimizing development costs.</p> + + +<h3 id="filtering">Filtering for business reasons</h3> + +<p>It’s possible that you may need to restrict your app’s availability for +business or legal reasons. For instance, an app that displays train schedules +for the London Underground is unlikely to be useful to users outside the United +Kingdom. Other apps might not be permitted in certain countries for business or +legal reasons. For cases such as these, Android Market itself provides +developers with filtering options that allow them control their app’s +availability for non-technical reasons.</p> + +<p>The help information for Android Market provides full details, but in a +nutshell, developers can use the Market publisher UI to:</p> + +<ul> +<li>List the countries an app is available in.</li> +<li>Select which carrier’s users are able to access the app.</li> +</ul> + +<p>Filtering for technical compatibility (such as required hardware components) +is always based on information contained within your <code>.apk</code> file. But +filtering for non-technical reasons (such as geographic restrictions) is always +handled in the Market user interface.</p> + +<h3 id="futureproofing">Future-proofing</h3> + +<p>There’s one additional quirk that we haven’t yet addressed: protecting apps +from changes made to future versions of Android. If the Android platform +introduces a new feature or changes how existing features are handled, what +happens to existing apps that were written without any knowledge of the new +behavior?</p> + +<p>Simply put, Android commits to not making existing apps available to devices +where they won’t work properly, even when the platform changes. The best way to +explain this is through examples, so here are two:</p> + +<ul> +<li>Android 1.0 through 1.5 required a 2 megapixel camera with auto-focus. +However, with version 1.6, Android devices were permitted to omit the auto-focus +capability, though a (fixed-focus) camera was still required. Some apps such as +barcode scanners do not function as well with cameras that do not auto-focus. To +prevent users from having a bad experience with those apps, existing apps that +obtain permission to use the Camera were assumed by default to require +auto-focus. This allowed Android Market to filter those apps from devices that +lack auto-focus.</li> + +<li>Android 2.2, meanwhile, allowed the microphone to be optional on some +devices, such as set-top boxes. Android 2.2 included a new feature ID for the +microphone which allows developers to filter their apps if necessary, but +— as with camera — apps that obtain permission to record audio are +assumed to require the microphone feature by default. If your app can use a +microphone but doesn’t strictly need it, you can explicitly state that you don’t +require it; but unless you do that, your app won’t be shown to devices without +microphones.</li> +</ul> + +<p>In other words, whenever Android introduces new features or changes existing +ones, we will always take steps to protect existing applications so that they +don’t end up being available to devices where they won’t work.</p> + +<p>This is implemented using the <code>aapt</code> tool in the SDK. To see which +features your app explicitly requires or is implicitly assumed to require, you +can use the command <code>aapt dump badging</code>.</p> + +<h3 id="conclusion">Conclusion</h3> + +<p>The goal of Android is to create a huge installed base for developers to take +advantage of. One of the ways we will achieve this is through different kinds of +hardware running the same software environment. But we also recognize that only +developers know which kinds of devices their apps make sense on. We’ve built in +tools to the SDK and set up policies and requirements to ensure that developers +remain in control of their apps, today and in the future. With the information +you just read, and the resources listed in the sidebar of this document, you +can publish your app with the confidence that only users who can run it will +see it.</p> + + +
\ No newline at end of file diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd new file mode 100644 index 000000000000..98f7a4f9f9b9 --- /dev/null +++ b/docs/html/guide/topics/data/backup.jd @@ -0,0 +1,761 @@ +page.title=Data Backup +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>Quickview</h2> + <ul> + <li>Back up your data to the cloud in case the user looses it</li> + <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li> + <li>Requires API Level 8</li> + </ul> + + <h2>In this document</h2> + <ol> + <li><a href="#Basics">The Basics</a></li> + <li><a href="#BackupAgent">Extending BackupAgent</a> + <ol> + <li><a href="#RequiredMethods">Required Methods</a></li> + <li><a href="#PerformingBackup">Performing backup</a></li> + <li><a href="#PerformingRestore">Performing restore</a></li> + </ol> + </li> + <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a> + <ol> + <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li> + <li><a href="#Files">Backing up Private Files</a></li> + </ol> + </li> + <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li> + <li><a href="#RequestingBackup">Requesting Backup</a></li> + <li><a href="#RequestingRestore">Requesting Restore</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.backup.BackupManager}</li> + <li>{@link android.app.backup.BackupAgent}</li> + <li>{@link android.app.backup.BackupAgentHelper}</li> + </ol> + +</div> +</div> + +<p>Android's {@link android.app.backup backup} service allows you to copy your persistent +application data to a remote "cloud" storage, in order to provide a restore point for the +application data and settings. If a user performs a factory reset or converts to a new +Android-powered device, the system automatically restores your backup data when the application +is re-installed. This way, your users are not required to reproduce their previous data or +application settings. This process is completely transparent to the user and does not affect the +functionality or user experience in your application.</p> + +<p>Android-powered devices that support the backup service provide a cloud storage area that +saves your backup data and a backup transport that delivers your data to +the storage area and back to the device. During a backup +operation, Android's Backup Manager requests backup data from your application, then delivers it to +the cloud storage using the backup transport. During a restore operation, the Backup Manager +retrieves the backup data from the backup transport and returns it to your application +so it can restore the data to the device. The backup service is <em>not</em> designed for data +synchronization (you do not have access the backup data, except during a restore operation on the +device).</p> + +<p>The cloud storage used for backup won't necessarily be the same on all Android-powered devices. +The cloud storage and backup transport may differ between devices and service providers. +Where the backup data is stored is transparent to your application, but you are assured that your +application data cannot be read by other applications.</p> + +<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can +differ from device to device, Android makes no guarantees about the security of your data while +using backup. You should be cautious about using backup to store sensitive data, such as usernames +and passwords.</p> + + +<h2 id="Basics">The Basics</h2> + +<p>To backup your application data, you need to implement a backup agent. Your backup +agent is called by the Backup Manager to provide the data you want to back up. It is also called +to restore your backup data when the application is re-installed. The Backup Manager handles all +your data transactions with the cloud storage and your backup agent handles all your data +transactions on the device.</p> + +<p>To implement a backup agent, you must:</p> + +<ol> + <li>Declare your backup agent in your manifest file with the <a +href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code +android:backupAgent}</a> attribute.</li> + <li>Define a backup agent by either:</p> + <ol type="a"> + <li><a href="#backupAgent">Extending BackupAgent</a> + <p>The {@link android.app.backup.BackupAgent} class provides the central interface with +which your application communicates with the Backup Manager. If you extend this class +directly, you must override {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()} to handle the backup and restore operations for your data.</p> + <p><em>Or</em></p> + <li><a href="#backupAgentHelper">Extending BackupAgentHelper</a> + <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient +wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code +you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more +"helper" objects, which automatically backup and restore certain types of data, so that you do not +need to implement {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}.</p> + <p>Android currently provides backup helpers that will backup and restore complete files +from {@link android.content.SharedPreferences} and <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p> + </li> + </ol> + </li> +</ol> + + + + +<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2> + +<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare +it in your manifest with the <a +href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code +android:backupAgent}</a> attribute in the <a +href="{@docRoot}guide/topics/manifest/application-element.html">{@code +<application>}</a> tag.</p> + +<p>For example:</p> + +<pre> +<manifest ... > + <application android:label="MyApplication" + <b>android:backupAgent="MyBackupAgent"</b>> + <activity ... > + ... + </activity> + </application> +</manifest> +</pre> + +<p>Another attribute you might want to use is <a +href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code +android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you +want to restore the application data regardless of the current application version compared to the +version that produced the backup data. (The default value is "{@code false}".) See <a +href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p> + +<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are +available only on devices running API Level 8 (Android 2.2) or greater, so you should also +set your <a +href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a> +attribute to "8". However, if you implement proper <a +href="{@docRoot}resources/articles/backward-compatibility.html">backward compatibility</a> in +your application, you can support this feature for devices running API Level 8 or greater, while +remaining compatible with older devices.</p> + + + + + +<h2 id="BackupAgent">Extending BackupAgent</h2> + +<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class +directly, but should instead <a href="BackupAgentHelper">extend BackupAgentHelper</a> to take +advantage of the built-in helper classes that automatically backup and restore your files. However, +you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p> +<ul> + <li>Version your data format. For instance, if you anticipate the need to revise the +format in which you write your application data, you can build a backup agent to cross-check your +application version during a restore operation and perform any necessary compatibility work if the +version on the device is different than that of the backup data. For more information, see <a +href="#RestoreVersion">Checking the Restore Data Version</a>.</li> + <li>Instead of backing up an entire file, you can specify the portions of data the should be +backed up and how each portion is then restored to the device. (This can also help you manage +different versions, because you read and write your data as unique entities, rather than +complete files.)</li> + <li>Back up data in a database. If you have an SQLite database that you want to restore when +the user re-installs your application, you need to build a custom {@link +android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then +create your table and insert the data during a restore operation.</li> +</ul> + +<p>If you don't need to perform any of the tasks above and want to back up complete files from +{@link android.content.SharedPreferences} or <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you +should skip to <a href="BackupAgentHelper">Extending BackupAgentHelper</a>.</p> + + + +<h3 id="RequiredMethods">Required Methods</h3> + +<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you +must implement the following callback methods:</p> + +<dl> + <dt>{@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()}</dt> + <dd>The Backup Manager calls this method after you <a href="#RequestBackup">request a +backup</a>. In this method, you read your application data from the device and pass the data you +want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing +backup</a>.</dd> + + <dt>{@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}</dt> + <dd>The Backup Manager calls this method during a restore operation (you can <a +href="#RequestRestore">request a restore</a>, but the system automatically performs restore when the +user re-installs your application). When it calls this method, the Backup Manager delivers your +backup data, which you then restore to the device, as described below in <a +href="#PerformingRestore">Performing restore</a>.</dd> +</dl> + + + +<h3 id="PerformingBackup">Performing backup</h3> + + +<p>When it's time to back up your application data, the Backup Manager calls your {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method. This is where you must provide your application data to the Backup Manager so +it can be saved to cloud storage.</p> + +<p>Only the Backup Manager can call your backup agent's {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method. Each time that your application data changes and you want to perform a backup, +you must request a backup operation by calling {@link +android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting +Backup</a> for more information). A backup request does not result in an immediate call to your +{@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs +backup for all applications that have requested a backup since the last backup was performed.</p> + +<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an +immediate backup operation from the Backup Manager with the <a +href="{@docRoot}guide/developing/tools/bmgr.html">bmgr tool</a>.</p> + +<p>When the Backup Manager calls your {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method, it passes three parameters:</p> + +<dl> + <dt>{@code oldState}</dt> + <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup +state provided by your application. This is not the backup data from cloud storage, but a +local representation of the data that was backed up the last time {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} was called (as defined by {@code newState}, below, or from {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}—more about this in the next section). Because {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} does not allow you to read existing backup data in +the cloud storage, you can use this local representation to determine whether your data has changed +since the last backup.</dd> + <dt>{@code data}</dt> + <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup +data to the Backup Manager.</dd> + <dt>{@code newState}</dt> + <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which +you must write a representation of the data that you delivered to {@code data} (a representation +can be as simple as the last-modified timestamp for your file). This object is +returned as {@code oldState} the next time the Backup Manager calls your {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState} +will point to an empty file next time Backup Manager calls {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()}.</dd> +</dl> + +<p>Using these parameters, you should implement your {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method to do the following:</p> + +<ol> + <li>Check whether your data has changed since the last backup by comparing {@code oldState} to +your current data. How you read data in {@code oldState} depends on how you originally wrote it to +{@code newState} (see step 3). The easiest way to record the state of a file is with its +last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code +oldState}: + <pre> +// Get the oldState input stream +FileInputStream instream = new FileInputStream(oldState.getFileDescriptor()); +DataInputStream in = new DataInputStream(instream); + +try { + // Get the last modified timestamp from the state file and data file + long stateModified = in.readLong(); + long fileModified = mDataFile.lastModified(); + + if (stateModified != fileModified) { + // The file has been modified, so do a backup + // Or the time on the device changed, so be safe and do a backup + } else { + // Don't back up because the file hasn't changed + return; + } +} catch (IOException e) { + // Unable to read state file... be safe and do a backup +} +</pre> + <p>If nothing has changed and you don't need to back up, skip to step 3.</p> + </li> + <li>If your data has changed, compared to {@code oldState}, write the current data to +{@code data} to back it up to the cloud storage. + <p>You must write each chunk of data as an "entity" in the {@link +android.app.backup.BackupDataOutput}. An entity is a flattened binary data +record that is identified by a unique key string. Thus, the data set that you back up is +conceptually a set of key-value pairs.</p> + <p>To add an entity to your backup data set, you must:</p> + <ol> + <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int) +writeEntityheader()}, passing a unique string key for the data you're about to write and the data +size.</li> + <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int) +writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write +from the buffer (which should match the size passed to {@link +android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li> + </ol> + <p>For example, the following code flattens some data into a byte stream and writes it into a +single entity:</p> + <pre> +// Create buffer stream and data output stream for our data +ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); +DataOutputStream outWriter = new DataOutputStream(bufStream); +// Write structured data +outWriter.writeString(playerName); +outWriter.writeInt(playerScore); +// Send the data to the Backup Manager via the BackupDataOutput +byte[] buffer = bufStream.toByteArray(); +int len = buffer.length; +data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len); +data.writeEntityData(buffer, len); +</pre> + <p>Perform this for each piece of data that you want to back up. How you divide your data into +entities is up to you (and you might use just one entity).</p> + </li> + <li>Whether or not you perform a backup (in step 2), write a representation of the current data to +the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object +locally as a representation of the data that is currently backed up. It passes this back to you as +{@code oldState} the next time it calls {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you +do not write the current data state to this file, then +{@code oldState} will be empty during the next callback. + <p>Again, the following example saves a representation of the data using the file's +last-modified timestamp:</p> + <pre> +FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); +DataOutputStream out = new DataOutputStream(outstream); + +long modified = mDataFile.lastModified(); +out.writeLong(modified); +</pre> + </li> +</ol> + +<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure +that you use synchronized statements while accessing the file so that your backup agent does not +read the file while an Activity in your application is also writing the file.</p> + + + + +<h3 id="PerformingRestore">Performing restore</h3> + +<p>When it's time to restore your application data, the Backup Manager calls your backup +agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so +you can restore it onto the device.</p> + +<p>Only the Backup Manager can call {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}, which happens automatically when the system installs your application and +finds existing backup data. However, you can request a restore operation for +your application by calling {@link +android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a +href="#RequestingRestore">Requesting restore</a> for more information).</p> + +<p class="note"><strong>Note:</strong> While developing your application, you can also request a +restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr +tool</a>.</p> + +<p>When the Backup Manager calls your {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()} method, it passes three parameters:</p> + +<dl> + <dt>{@code data}</dt> + <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup +data.</dd> + <dt>{@code appVersionCode}</dt> + <dd>An integer representing the value of your application's <a +href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> +manifest attribute, as it was when this data was backed up. You can use this to cross-check the +current application version and determine if the data format is compatible. For more +information about using this to handle different versions of restore data, see the section +below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd> + <dt>{@code newState}</dt> + <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which +you must write the final backup state that was provided with {@code data}. This object is +returned as {@code oldState} the next time {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} is called. Recall that you must also write the same {@code newState} object in the +{@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} callback—also doing it here ensures that the {@code oldState} object given to +{@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} is valid even the first time {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} is called after the device is restored.</dd> +</dl> + +<p>In your implementation of {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} to iterate +through all entities in the data set. For each entity found, do the following:</p> + +<ol> + <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li> + <li>Compare the entity key to a list of known key values that you should have declared as static +final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of +your known key strings, enter into a statement to extract the entity data and save it to the device: + <ol> + <li>Get the entity data size with {@link +android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li> + <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int) +readEntityData()} and pass it the byte array, which is where the data will go, and specify the +start offset and the size to read.</li> + <li>Your byte array is now full and you can read the data and write it to the device +however you like.</li> + </ol> + </li> + <li>After you read and write your data back to the device, write the state of your data to the +{@code newState} parameter the same as you do during {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()}. +</ol> + +<div class="special"> +<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a +href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code +ExampleAgent}</a> class in the <a +href="{@docRoot}}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample +application.</p> +</div> + + + + + + +<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2> + +<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want +to back up complete files (from either {@link android.content.SharedPreferences} or <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>). +Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less +code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement +{@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}.</p> + +<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must +use one or more backup helpers. A backup helper is a specialized +component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and +restore operations for a particular type of data. The Android framework currently provides two +different helpers:</p> +<ul> + <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link +android.content.SharedPreferences} files.</li> + <li>{@link android.app.backup.FileBackupHelper} to backup files from <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li> +</ul> + +<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only +one helper is needed for each data type. That is, if you have multiple {@link +android.content.SharedPreferences} files, then you need only one {@link +android.app.backup.SharedPreferencesBackupHelper}.</p> + +<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do +the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p> +<ol> + <li>Instantiate in instance of the desired helper class. In the class constructor, you must +specify the appropriate file(s) you want to backup.</li> + <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()} +to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li> +</ol> + +<p>The following sections describe how to create a backup agent using each of the available +helpers.</p> + + + +<h3 id="SharedPreferences">Backing up SharedPreferences</h3> + +<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must the +name of one or more {@link android.content.SharedPreferences} files.</p> + +<p>For example, to back up a {@link android.content.SharedPreferences} file named +"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks +like this:</p> + +<pre> +public class MyPrefsBackupAgent extends BackupAgentHelper { + // The name of the SharedPreferences file + static final String PREFS = "user_preferences"; + + // A key to uniquely identify the set of backup data + static final String PREFS_BACKUP_KEY = "prefs"; + + // Allocate a helper and add it to the backup agent + void onCreate() { + SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); + addHelper(PREFS_BACKUP_KEY, helper); + } +} +</pre> + +<p>That's it! That's your entire backup agent. The {@link +android.app.backup.SharedPreferencesBackupHelper} includes all the code +needed to backup and restore a {@link android.content.SharedPreferences} file.</p> + +<p>When the Backup Manager calls {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform +backup and restore for your specified files.</p> + +<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so +you can safely read and write the shared preferences file from your backup agent and +other activities.</p> + + + +<h3 id="Files">Backing up other files</h3> + +<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of +one or more files that are saved to your application's <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a> +(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same +location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes +files).</p> + +<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link +android.app.backup.BackupAgentHelper} looks like this:</p> + +<pre> +public class MyFileBackupAgent extends BackupAgentHelper { + // The name of the SharedPreferences file + static final String TOP_SCORES = "scores"; + static final String PLAYER_STATS = "stats"; + + // A key to uniquely identify the set of backup data + static final String FILES_BACKUP_KEY = "myfiles"; + + // Allocate a helper and add it to the backup agent + void onCreate() { + FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS); + addHelper(FILES_BACKUP_KEY, helper); + } +} +</pre> + +<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and +restore files that are saved to your application's <a +href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p> + +<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To +ensure that your backup agent does not read or write your files at the same time as your activities, +you must use synchronized statements each time you perform a read or write. For example, +in any Activity where you read and write the file, you need an object to use as the intrinsic +lock for the synchronized statements:</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<p><strong>Interesting Fact:</strong></p> +<p>A zero-length array is lighter-weight than a normal Object, so it's great for an +intrinsic lock.</p> +</div> +</div> + +<pre> +// Object for intrinsic lock +static final Object[] sDataLock = new Object[0]; +</pre> + +<p>Then create a synchronized statement with this lock each time you read or write the files. For +example, here's a synchronized statement for writing the latest score in a game to a file:</p> + +<pre> +try { + synchronized (MyActivity.sDataLock) { + File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES); + RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw"); + raFile.writeInt(score); + } +} catch (IOException e) { + Log.e(TAG, "Unable to write to file"); +} +</pre> + +<p>You should synchronize your read statements with the same lock.</p> + +<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()} to synchronize the backup and restore operations with the same +intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following +methods:</p> + +<pre> +@Override +public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) throws IOException { + // Hold the lock while the FileBackupHelper performs backup + synchronized (MyActivity.sDataLock) { + super.onBackup(oldState, data, newState); + } +} + +@Override +public void onRestore(BackupDataInput data, int appVersionCode, + ParcelFileDescriptor newState) throws IOException { + // Hold the lock while the FileBackupHelper restores the file + synchronized (MyActivity.sDataLock) { + super.onRestore(data, appVersionCode, newState); + } +} +</pre> + +<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the +{@link android.app.backup.BackupAgent#onCreate()} method and override {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} and {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) +onRestore()} to synchronize read and write operations.</p> + +<div class="special"> +<p>For an example implementation of {@link +android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the +{@code FileHelperExampleAgent} class in the <a +href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample +application.</p> +</div> + + + + + + +<h2 id="RestoreVersion">Checking the Restore Data Version</h2> + +<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version +of your application, as defined by your manifest file's <a +href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> +attribute. Before the Backup Manager calls your backup agent to restore your data, it +looks at the <a +href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code +android:versionCode}</a> of the installed application and compares it to the value +recorded in the restore data set. If the version recorded in the restore data set is +<em>newer</em> than the application version on the device, then the user has downgraded their +application. In this case, the Backup Manager will abort the restore operation for your application +and not call your {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} +method, because the restore set is considered meaningless to an older version.</p> + +<p>You can override this behavior with the <a +href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code +android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code +false}" to indicate whether you want to restore the application regardless of the restore set +version. The default value is "{@code false}". If you define this to be "{@code true}" then the +Backup Manager will ignore the <a +href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a> +and call your {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} +method in all cases. In doing so, you can manually check for the version difference in your {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} +method and take any steps necessary to make the data compatible if the versions conflict.</p> + +<p>To help you handle different versions during a restore operation, the {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} +method passes you the version code included with the restore data set as the {@code appVersionCode} +parameter. You can then query the current application's version code with the {@link +android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p> + +<pre> +PackageInfo info; +try { + String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}(); + info = {@link android.content.ContextWrapper#getPackageManager +getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int) +getPackageInfo}(name,0); +} catch (NameNotFoundException nnfe) { + info = null; +} + +int version; +if (info != null) { + version = info.versionCode; +} +</pre> + +<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo} +to the {@code appVersionCode} passed into {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}. +</p> + +<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting +<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code +android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your +application that supports backup does not properly account for variations in your data format during +{@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}, +then the data on the device could be saved in a format incompatible with the version currently +installed on the device.</p> + + + +<h2 id="RequestingBackup">Requesting Backup</h2> + +<p>You can request a backup operation at any time by calling {@link +android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd +like to backup your data using your backup agent. The Backup Manager then calls your backup +agent's {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()} method at an opportune time in the future. Typically, you should +request a backup each time your data changes (such as when the user changes an application +preference that you'd like to back up). If you call {@link +android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup +Manager requests a backup from your agent, your agent still receives just one call to {@link +android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) +onBackup()}.</p> + +<p class="note"><strong>Note:</strong> While developing your application, you can request a +backup and initiate an immediate backup operation with the <a +href="{@docRoot}guide/developing/tools/bmgr.html">bmgr +tool</a>.</p> + + +<h2 id="RequestingRestore">Requesting Restore</h2> + +<p>During the normal life of your application, you shouldn't need to request a restore operation. +They system automatically checks for backup data and performs a restore when your application is +installed. However, you can manually request a restore operation by calling {@link +android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In +which case, the Backup Manager calls your {@link +android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()} +implementation, passing the data from the current set of backup data.</p> + +<p class="note"><strong>Note:</strong> While developing your application, you can request a +restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr +tool</a>.</p> + diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd index 93c5fb8d06be..3dfeedfe0cd6 100644 --- a/docs/html/sdk/ndk/index.jd +++ b/docs/html/sdk/ndk/index.jd @@ -72,8 +72,8 @@ Android NDK, Revision 4</a> <em>(May 2010)</em> <ul> <li>Provides a simplified build system through the new <code>ndk-build</code> build command. </li> -<li>Adds support for easy native debugging of generated machine code through the new -<code>ndk-gdb</code> command.</li> +<li>Adds support for easy native debugging of generated machine code on production +devices through the new <code>ndk-gdb</code> command.</li> <li>Adds a new Android-specific ABI for ARM-based CPU architectures, <code>armeabi-v7a</code>. The new ABI extends the existing <code>armeabi</code> ABI to include these CPU instruction set extensions: @@ -81,7 +81,8 @@ ABI to include these CPU instruction set extensions: <li>Thumb-2 instructions</li> <li>VFP hardware FPU instructions (VFPv3-D16)</li> <li>Optional support for ARM Advanced SIMD (NEON) GCC intrinsics and VFPv3-D32. -Supported by devices such as Verizon Droid, Google Nexus One, and others.</li> +Supported by devices such as Verizon Droid by Motorola, Google Nexus One, and +others.</li> </ul> <li>Adds a new <code>cpufeatures</code> static library (with sources) that lets your app detect the host device's CPU features at runtime. Specifically, |