ラベル Froyo の投稿を表示しています。 すべての投稿を表示
ラベル Froyo の投稿を表示しています。 すべての投稿を表示

2010年5月31日月曜日

Android Android 2.2 データバックアップ

これを書いた 2010/5/31 にはなかった Registering for Android Backup Service という項が追加されていたので、追記しました。 2011/1/1


Android - Froyo - Data Backup

Android 2.2 からアプリケーションのデータのバックアップができるようになりました。
これまでは、アプリケーションのデータベースなどに保存されていたデータは、アプリケーションをアインストールすると削除されていました(アップデート時は保持される)。そのため、再インストール時(一度アインストールしてから、再びインストール)や、別の端末に切り替えたとき、そのデータを移行することができませんでした。
Froyo からはそれができるようになります。




元の記事はこちら↓
http://developer.android.com/intl/ja/sdk/android-2.2.html#api


Android 2.2 から、プラットフォームは 一般的なバックアップサービスを提供するようになりました。
これにより、ユーザーがデバイスを切り替えたり、アプリケーションを再インストールしたときに、ユーザーのデータを維持できるように、アプリケーションはユーザのデータをバックアップしリストアできるようになりました。
Backup Manager はアプリケーションのデータを、クラウド内のバックアップストレージ領域へ/から転送する動作を処理します。
Backup Manager は任意のデータからファイルまで、どんなタイプのデータも保存でき、バックアップと復元操作を管理します。
より詳しい情報は Data Backup を参照してください。




Data Backup

元の記事はこちら↓
ttp://developer.android.com/guide/topics/data/backup.html

Android's backup serveice によって、アプリケーションのデータをリモートの "cloud" ストレージにコピーすることができます。この "cloud" ストレージは、アプリケーションデータや設定情報のリストアポイントを提供するためのものです。
もし、ユーザーがファクトリーリセットをしたり、新しい Android デバイスに切り替えた場合、システムはアプリケーションのインストール時に、自動的にユーザーのバックアップデータをリストアします。
この方法によって、ユーザーはそのアプリケーションの以前のデータや設定情報を再生成する必要がなくなります。
このプロセスはユーザーに完全に透明で、アプリケーションの機能やユーザーエクスペリエンスに影響をあたえることはありません。


backup service が提供されている Android搭載デバイスは、アプリケーションのバックアップデータを保存するためのクラウドストレージ領域と、データをストレージ領域に届けデバイスに戻すためのバックアップ転送を提供します。
バックアップ操作の間、Android's Backup Manager はアプリケーションからバックアップデータを要求し、それをバックアップ転送を使ってクラウドストレージへ届けます。
リストア操作の間は、Backup Manager はバックアップ転送からバックアップデータを受け取り、それをアプリケーションに返します。そのため、アプリケーションはデバイスにデータをリストアできます。
backup service はデータ同期用にデザインされていません。
(デバイスへのリストア処理時以外は、バックアップデータへのアクセス権はありません)


バックアップに使われるクラウドストレージは必ずしも全ての Android 搭載デバイス上で同じである必要はありません。クラウドストレージとバックアップ転送は複数のデバイスとサービスプロバイダーの間で異なることがあります。
保存されたバックアップデータは、そのアプケーションに対して透明ですが、そのアプリケーションのデータは他のアプリケーションから読めないことが保証されています。


注意:クラウドストレージと転送サービスはデバイス間で異なることがあるので、Android はバックアップされるデータのセキュリティについて保障しません。あなたは、ユーザー名やパスワードのような機密データを保存する場合、バックアップの使用について慎重になる必要があります。



The Basics

アプリケーションのバックアップをするためには、backup agent を実装する必要があります。

Backup Manager から呼ばれる backup agent はユーザーがバックアップしたいデータを提供します。また、アプリケーションが再インストールされたときに、バックアップデータをリストアするためにも呼ばれます。Backup Manager はクラウドストレージでの全てのユーザーデータトランザクションを処理します。一方、backup agent はデバイス上での全てのユーザーデータトランザクションを処理します。

backup agent を実装するには

 1. AndroidManifest.xml の android:backupAgent 属性で
  backup agent を宣言する

 2. backup agent を定義する(方法は次のいずれか)

  a. BackupAgent を拡張する   
    BackupAgent クラスは、アプリケーションが BackupManager と
    通信するための中心的インタフェースを提供します。もし、
    このクラスを直接拡張したいなら、データのバックアップと
    リストアを処理するための onBackup()onRestore()
    オーバーライドしなければなりません。

  b. BackupAgentHelper を拡張する   
    BackupAgentHelper クラスは BackupAgent クラスの便利な
    ラッパーを提供します。これにより、書くべきコード量が
    最小化できます。 BackupAgentHelper 内で、特定のタイプの
    データを自動でバックアップ・リストアするために、1つ以上の
    "helper" オブジェクトを使う必要があります。
    この場合、onBackup() と onRestore() を実装する必要は
    ありません。

  Android で現在提供されている backup helper は、SharedPreferencesinternal storage の完全なファイルをバックアップ・リストアします。



Declaring the Backup Agent in Your Manifest

まず、backup agent のクラス名を決めます。
次に、AndroidManifest.xml の <application> タグ内の android:backupAgent 属性でそのクラスを宣言します。

例えば、

<manifest ... >
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
<activity ... >
...
</activity>
</application>
</manifest>


これ以外に関係ある属性として、android:restoreAnyVersion があります。
この属性は boolean値をとり、バックアップデータを生成したときのアプリケーションのバーションと、現在のバーションの比較に関係なくアプリケーションのデータをリストアしたいかどうかを表します。(デフォルトは "false")より詳しい情報は Checking the Restore Data Version を見てください。

注: backup service とその API は API Level 8 (Android 2.2) もしくはそれ以上で走っているデバイス上でのみ使用可能なため、"android:minSdkVerions" 属性は 8 に設定すべきです。しかし、もしアプリケーションで適切な後方互換性を実装するなら、古いデバイスとの互換性を維持しながら、API Level 8 以上のデバイスに対してこの機能をサポートすることができます。


Registering for Android Backup Service

Android 2.2 以上が走っているデバイスに対して、Google は Android Backup Service を使った backup 転送を提供します。

Android Backup Service を使った backup をアプリケーションで行うために、Backup Service Key を受信するためのサービスにアプリケーションを登録しなければなりません。受け取った Backup Service Key はアプリケーションの Android manifest で定義します。

Backup Service Key を取得するには、Android Backup Service に登録します。登録すると、Backup Service Key が提供されるので、適切な <meta-data> XML コードとともに Android manifest の <application< エレメント内に定義します。


<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="INSERT YOUR API KEY HERE" />
</application>


android:name には "com.google.android.backup.api_key" を指定し、android:value には Android Backup Service 登録で受け取った Backup Service Key を指定します。

注意: Android Backup Service によって提供される backup 転送は、backup をサポートする全ての Android 搭載デバイスで使用できることを保証しません。いくつかのデバイスは異なる転送を使ったバックアップをサポートし、いくつかのデバイスはバックアップ自体をサポートしないでしょう。デバイスがどの転送を使っているのかアプケーションから知る方法はありません。アプリケーションがバックアップを実装するなら、常に Backup Service Key を含むことで、デバイスが Android Backup Service 転送を使う場合にバックアップを実行することができます。デバイスが Android Backup Service を使わない場合は、Backup Service Key 用の <meta-data> エレメントは無視されます。


Extending BackupAgent

 一般的ではないので、後回し
 いずれ書きます。。。




Extending BackupAgentHelper

BackupAgentHelper の実装では、1つ以上の backup helpers を使う必要があります。
backup helper は BackupAgentHelper が特定のタイプのデータをバックアップ・リストアするために召喚する専用のコンポーネントです。
現在のフレームワークでは次の2つが提供されています。

 ・SharedPreferencesBackupHelper
    SharedPreferences のファイルをバックアップする

 ・FileBackupHelper
    internal storage のファイルをバックアップする


BackupAgentHelper には複数の helper を持たせることができますが、各データタイプに対して helper が1つあれば十分です。つまり、もし複数の SharedPreferences ファイルを持っていても、必要な SharedPreferencesBackupHelper は1つだけです。


BackupAgentHelper に追加したい各 helper に対して、 onCreate() で以下の処理が必要です。

  1. 必要な helper クラスのインスタンスを作成し、クラスの
   コンストラクタで、バックアップしたい適切なファイルを指定する


  2. addHelper() を呼んで、 helper を BackupAgentHelper に
   追加する



例1 Backing up SharedPreferences

こんな感じ


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
public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}


ここで、 "user_preferences" が SharedPreferences ファイルの名前です。
これで全体の backup agent は完成です。
Backup Manager が onBackup() や onRestore() を読んだとき、BackupAgentHelper はバックアップ・リストア処理を行うために backup helpers を呼びます。

注: SharedPreferences はスレッドセーフなので、backup agent と 他のアクティビティの間で安全に shared preferences の読み・書きができます。


例2 Backing up other files

FileBackupHelper のインスタンスを作成する場合、アプリケーションの internal storage に保存されている1個以上のファイル名を含める必要があります。
(internal storage は、getFilesDir() で指定されたディレクトリで、openFileOutput() でファイルが書き込まれる場所と同じです。)

こんな感じ


public class MyFileBackupAgent extends BackupAgentHelper {

// The name of the file in internal storage
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
public void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
}


ここで、"scores" と "stats" は internal storage 内のファイル名です。

FileBackupHelper は アプケーションの internal storage 保存されたファイルをバックアップ&リストアするのに必要な全コードを含みます。

しかし、internal storage のファイルへの書き込み/読み出しはスレッドセーフではありません
backup agent はアクティビティと同時に読み/書きしないことを保証するために、読み/書きを実行するごとに同期された状態を使わなければなりません。
例えば、あるファイルを読み/書きするアクティビティでは、同期された状態のために intrinsic lock として使うオブジェクトが必要です。

こんな感じで定義

// Object for intrinsic lock
static final Object[] sDataLock = new Object[0];


Interesting Fact:
長さ 0 の配列は、通常のオブジェクトよりも軽い、なので intrinsic lock に最適!

そして、ファイルを読み/書きする毎にこの lock を使って同期された状態を生成します。

例えば、こんな感じ

try {
synchronized (MyActivity.sDataLock) {
File dataFile = new File(getFilesDir(), TOP_SCORES);
RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
raFile.writeInt(score);
}
} catch (IOException e) {
Log.e(TAG, "Unable to write to file");
}


同じ lock を使って、読み込み状態も同期します。

そして、 BackupAgentHelper で、同じ intrinsic lock を使ってバックアップとリストア操作を同期させるために onBackup() と onRestore() を Override しなければなりません。

例えば、こんな感じ

@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);
}
}


サンプルプロジェクトはこちら
http://developer.android.com/resources/samples/BackupRestore/index.html




Checking the Restore Data Version

Backup Manager がデータをクラウドストレージに保存した時、自動的にアプリケーションのバージョン(AndroidManifest.xml の android:versionCode 属性の値)も一緒に保存されます。
データをリストアするために backup agent を呼ぶ前に、Backup Manager は、インストールされているアプリケーションの android:versionCode を見に行き、リストアされるデータセットに記録されているバージョン値と比較します。
もし、記録されているバージョン値がデバイス上のアプリケーションのバージョンよりも新しい場合、ユーザーはアプリケーションをダウングレードしていることになります。この場合、Backup Manager はリストア操作を中止し、onRestore() を呼びません。なぜなら、リストアセットは古いバージョンには無意味と考えられるためです。

android:restoreAnyVersion 属性を設定することで、この振舞を override することができます。
この属性は "true" もしくは "false" を取り、リストアセットのバージョンにかかわらずアプリケーションのデータをリストアするかどうかを示します。
デフォルトの値は "false " です。もし、この属性を "true" に設定した場合、Backup Manager は android:versionCode の値を無視し、いつでも onRestore() を呼びます。そうすると、onRestore() でバージョンの違いをマニュアル的にチェックすることができ、バージョン競合の場合にデータ互換性を保つために必要な処理を行うことができます。

リストア操作のときに異なるバージョンを扱う手助けとして、onResotre() の第2引数で、リストアデータにセットされたバージョンコードを取得することができます。
onRestore (BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)

アプリケーションの現在のバージョンは PackageInfo.versionCode で取得できる。
こんな感じ

@Override
public void onRestore (onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
super.onRestore(data, appVersionCode, newState);

PackageInfo info;
try {
String name = getPackageName();
info = getPackageManager().getPackageInfo(name,0);
} catch (NameNotFoundException nnfe) {
info = null;
}

if (info != null) {
if (appVersionCode != info.versionCode) {
....
}
else
....
}
}
}


注意:android:restoreAnyVersion 設定を "true" にした場合の特定の結果について理解してください。もし、バックアップをサポートしているアプリケーションの各バージョンにデータフォーマットの変動がある場合を onResore() 内で適切に扱わない場合、、デバイス上のデータは、現在インストールされているバージョンと非互換の形式で保存されます。




Requesting Backup

バックアップ操作は dataChanged() を呼ぶことでいつでも要求できます。このメソッドは Backup Manager に backup agent を使ってデータをバックアップしたいことを知らせます。そうすると、Backup Manager は呼び出しが可能になった時点で、backup agent の onBackup() を呼び出します。 典型的に、データが変化した毎にバックアップを要求すべきです。(例えば、ユーザーがバックアップしておきたいアプリケーションの設定を変更したときなど)
もし、複数回連続して dataChanged() を呼び出すと、Backup Manager が agent からバックアップを1回要求する前に、agent はまだ onBackup() を1回だけ受け取ります。

Note: アプリケーションを開発している間は、 bmgr tool を使うことで、バックアップを要求することができ、すぐにバックアップを開始することができます。




Requesting Restore

通常のライフサイクルでは、リストア操作要求する必要はありません。システムが自動的にバックアップデータをチェックして、アプリケーションのインストール時にリストアを実行します。しかし、もし必要ならば requestRestore() を呼ぶことで、マニュアル的にリストア操作を要求することができます。この場合、 Backup Manager は onRestore() 実装を呼び、バックアップデータの現在のセットからデータを渡します。




Developing and Testing Your Backup Agent

backup agent の 開発とテスト :

 Backup Agent をテストするには、bmgr toolを使って、次の手順を行ないます。

 1. アプリケーションを適切な Android system image にインストールする

  ・ エミュレータを使う場合は Android 2.2 (API Level 8)
    以上のAVDを作成する

  ・ デバイスを使う場合は、Android 2.2 以上が走っていて、
    かつビルトインの Android Market がインストールされている
    デバイスが必要


 2. バックアップを有効にする

  ・ エミュレータを使う場合、SDK tools/ 内の adb コマンドを使う

  ・ デバイスを使う場合、設定(Setting) → プライバシー(Privacy) で
    データのバックアップ(Back up my data) と 自動復元
    (Automatic restore) を有効にする

< adb shell bmgr enable true


 3. アプリケーションを起動して、いくつかのデータを初期化する

  データの変化時に dataChanged() メソッドを呼ぶなど適切に
  バックアップ処理が実装されている場合は、Backup Manager
  キューにバックアップリクエストが追加される。
  テストを目的として次のコマンドでリクエストを生成することができる


< adb shell bmgr backup your.package.name


 4. バックアップ処理を初期化する

  Backup Manager にキュー内の全てのバックアップリクエストを処理させる


< adb shell bmgr run


 5. アプリケーションをアンインストールする


< adb uninstall your.package.name


 6. アプリケーションを再インストールする

backup agent が成功していれば、step 4 で初期化したデータがリストアされる

2010年5月24日月曜日

Android Android 2.2 外部メディア (SDcard) へのインストール指定

Android - Froyo - App installation on external storage media

Android 2.2 (Froyo) から、アプリケーションはどこにインストールされるかを指定することができるようになりました。
つまり、マーケットからインストールするときに、内部メモリではなく SDcard のような外部メディアにインストールさせることが可能になりました。
*あくまでのアプリ側が自分がどこにインストールされるかを指定できるということです。ユーザーが指定できるわけではありません。

元記事はこちら↓ (誤訳の責任はとりません)
http://developer.android.com/intl/ja/sdk/android-2.2.html#api

具体的には、AndroidManifest.xml の
< manifest > タグに

 android:installLocation

を設定します。
設定できる値は

 ・"internalOnly"
 ・"preferExternal"
 ・"auto"

の3つです。
こんな感じ


<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="preferExternal"
... />


by App Install Location

インストール時にシステムは "android:installLocation" の値を参照して、(可能な場合は)適切な位置にインストールします。
もし、アプリケーションが外部メディアにインストールするように要求している場合、システムはアプリケーションを外部メディアのプライベートな暗号化パーティションにインストールします。
一度アプリケーションが外部にインストールされると、ユーザーはそのアプリケーションの保存場所を内部メモリに移動させることが可能になります(ユーザー設定のアプリケーションの管理で行う)。

デフォルトでは、明示的に外部メディアへのインストールを要求する場合以外は、システムはすべてのアプリケーションをデバイスの内部メモリにインストールします。
これは、システムは常に内部メモリに従来のアプリケーションをインストールすることを意味します。なぜなら、従来のアプリケーションには "android:installLocation" 属性へのアクセスがないからです。
しかし、もし必要ならば、古いバーションのプラットフォームでは内部メモリにインストールし、Android 2.2 とそれ以降のプラットフォームでは外部メディアにインストールするように、従来のアプリケーションを設定し、コンパイルすることは可能です。

デバイスの外部メディアにインストールを要求することは、すべてのアプリケーションにとって適していないことに注意してください。特に、外部メディアは取り外しが可能で、アンマウント/再マウントによってユーザ経験やシステム設定を混乱させる可能性があります。

適切なインストール場所についての詳しい情報は
 App Install Location
を参照してください。
どんなアプリケーションが外部メディアへのインストールに適しているかの議論が含まれています。






App Install Location

元記事はこちら↓ (誤訳の責任はとりません)
http://developer.android.com/intl/ja/guide/appendix/install-location.html

*上記とかぶっている部分は除いてあります。

"android:installLocation" 属性が宣言されていない場合は、アプリケーションは内部ストレージにだけインストールされます(外部ストレージに移動はできません)。

アプリケーションを外部ストレージにインストールする場合は、"android:installLocation" に "preferExternal" もしくは "auto" を指定します。

"preferExternal" を宣言した場合、アプリケーションは外部ストレージへのインストールを要求しますが、システムはそのアプリケーションが外部ストレージにインストールされるかどうかは保証しません。
例えば、外部ストレージが満杯の場合、システムは内部ストレージにインストールします。ユーザーはアプリケーションの場所を(内部と外部ストレージの間を)移動することができます。

"auto" を宣言した場合、アプリケーションが外部ストレージにインストールされる可能性を示しますが、インストール場所の優先順位は持っていない。システムがいくつかのファクターをもとにどこにインストールするかを決定します。この場合もユーザーはアプリケーションの場所を移動することができます。

外部ストレージにアプリケーションがインストールされた場合

 ・外部ストレージがデバイスにマウントされている限り、
  アプリケーションのパフォーマンスには影響しない

 ・.apk ファイルが外部ストレージに保存されていても、
  プライベートユーザーデータ、データベース、
  最適化された .dex ファイル、引用されるネイティブコードは
  全て内部デバイスメモリに保存される

 ・アプリケーションが保存される一意のコンテナは、
  ランダムに生成されたキーで暗号化されており、
  アプリケーションをインストールしたオリジナルのデバイスだけが
  複合化できる。つまり、SD card へのアプリケーションの
  インストールは単一のデバイスに対してのみ働く

 ・ユーザーはシステム設定で、アプリケーションの保存先を
  内部ストレージに移動できる

*警告:PCとファイルを共有するためにUSBマスストレージを有効にした場合や、SD card をアンマウントした場合、外部ストレージで走っているすべてのアプリケーションはただちに kill されます




Backward Compatibility

外部ストレージへのインストールを許可し、API Level 8 よりも下のバージョンとの互換性を残す方法

 1 android:installLocation 属性を含み、"auto" もしくは
  "preferExternal" を宣言する

 2 android:minSdkVersion 属性を残し("8" より小さいなにか)、
  アプリケーションのコードがそのレベルと互換性のあるAPIだけ
  使っていることを確かめる

 3. アプリケーションをコンパイルするときにビルドターゲットを
  API Level 8 にする。これは、Level 8 よりも古い Android
  ライブラリが android:installLocation を理解できないため、
  前のバージョンではコンパイルできない。

この方法でコンパイルしたアプリケーションは、API Level が 8 よりも小さいプラットフォームでは "android:installLocation" 属性は無視されて内部ストレージにインストールされ、8 より大きいプラットフォームでは外部ストレージにインストールされる。

*注意: minSdkVersion が "8" より小さい場合、後方互換性を保つため、API Level 8 で紹介されたAPI は使ってはいけない




Applications That Should NOT Install on External Storage

外部ストレージがアンマウントされた場合、外部ストレージで走っているアプリケーションは kill される。よって、次のような特徴をもつアプリケーションは外部ストレージに保存すべきではない。

・Services
  ただし、ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
  broadcast Intent をトリガーとして登録し、再スタートできる

・Alarm Services
  Service と同じ方法で再マウント時に再登録できる

・Input Method Engines
  アンマウントされた場合、IME はデフォルトに置き換えられる。
  再マウント時にユーザーが再設定する必要がある

・Live Wallpapers
  アンマウントされた場合、Live Wallpaper はデフォルトに
  置き換えられる。再マウント時にユーザーが再度選択する必要がある

・Live Folders
  アンマウントされた場合、ホームスクリーンから Live Folder
  は削除される。再マウント時にユーザーが再度ホームスクリーンに
  追加する必要がある

・App Widgets
  アンマウントされた場合、ホームスクリーンから App Widget は
  削除される。再マウント時にユーザーがホームアプリケーションを
  システムリセットするまで(通常はリブートするまで)、
  ユーザーは App Widget を選択できない

・Account Managers
  AccountManager によって作成されたアカウントは外部ストレージが
  再マウントされるまで見えなくなる

・Sync Adapters
  AbstractThreadedSyncAdapter とその全同期機能は外部ストレージが
  再マウントされるまで働かなくなる

・Device Administrators
  DeviceAdminReceiver とその全ての管理能力は無効になり、
  デバイスの機能に対して予測不可能な結果を持つ可能性があり、
  外部ストレージが再マウントされた後も続く可能性がある


デフォルトでは内部メモリインストールされるため、特にすることはないが、外部ストレージに保存すべきでないことを明示する場合は "android:installLocation" に "internalOnly" を宣言してください。




Applications That Should Install on External Storage

簡単にいえば、上記であげた特徴を持たないアプリケーションは外部ストレージに保存しても安全である。サイズの大きいゲームなどは、外部ストレージに保存すべきアプリケーションのタイプの1つである。なぜなら、ゲームは典型的にアクティブではない場合に追加のサービスを提供しないため。
外部ストレージにアクセスできなくなり、ゲームのプロセスは kill された後、ストレージが再び使用可能になった場合目に見える効果はなく、ユーザーはゲームを再起動する必要があります。(通常の Activity lifecycle で適切にゲームが保存されていると仮定)

もし、アプリケーションが APK ファイルとして数メガバイトを要求する場合、ユーザーが内部ストレージのスペースを確保するために、アプリケーションが外部ストレージに保存できるようにするかどうか慎重に検討する必要がある。

Android Android 2.2 Platform Highlights

Android 2.2 Platform Highlights
を訳してみました。

*誤訳があっても責任はとりません。





このページは Android 2.2 のハイライトなので、より詳しい内容はこちらを
参照してください
Android 2.2 version notes.




New User Features

Home

新しいホームスクリーンにはチップスウィジェットが配置されるようになりました。
これは、新しいユーザーにショートカットやウィジェットをホームスクリーンに設置する方法や、複数のホーム画面を使用する方法をアシストします。

電話、アプリケーションランチャー、ブラウザのショートカットがホームスクリーンに配置されるようになりました。
5画面すべてに表示されるので、これらのアプリへのアクセスが簡単になりました。



Exchange support

端末のロック解除に数字ピンまたは英数字のパスワードオプションを追加して、セキュリティを強化しました。
Exchange管理者はデバイス間でパスワードポリシーを強制することができます。

リモートワイプ: Exchange管理者はリモートで端末をファクトリーリセットすることができます。これにより、紛失・盗難した場合に端末内のデータを保護することができます。

Echangeカレンダーがカレンダーアプリケーションでサポートされるようになりました。

Auto-discovery: 自分のユーザ名とパスワードを知っているだけで、Exchange アカウントとの同期が簡単にセットアップできます。(Exchange 2007および以降で可能)

グローバルアドレスリストのルックアップが、メールアプリケーションで利用できるようになりました。
これにより、ディレクトリから、受信者の名前の自動補完ができるようになりました。



Camera and Gallery

ギャラリーで、ズームジェスチャーを使って、ピクチャ集をのぞき込めるようになりました。

カメラの画面上のボタンでは、ズーム、フラッシュ、ホワイトバランス、ジオタグ、フォーカス、露出を簡単に設定できます。
ビデオカメラでは、サイズ/品質をMMSおよびYouTube用に簡単に設定できます。

LED フラッシュがビデオカメラでも使えるようになりました。
これにより、夜や低照度でも撮影することができるようになりました。



Portable hotspot

Nexus One のような一部のデバイスは、最大8つのデバイスが共有することができるWi-Fiホットスポットになることができます。

コンピュータにUSBケーブルでAndroid搭載携帯電話を接続することにより、WindowsまたはLinuxラップトップの3G接続として使用することができます。接続は、2つのデバイス間で共有されます。



Multiple keyboard languages

多言語のユーザーは、キーボードに複数の言語を追加することができます。
また、スペースバーをスワイプすることで、複数のラテンベースの入力言語を切り替えることが可能です。にこれは、auto-suggest dictionary と同じようにキーを切り替えます。



パフォーマンスの向上
V8エンジンを使用することで、JavaScript重いページの読み込みを高速化することが可能になり、ブラウザのパフォーマンスが改善しました。

Dalvik Performance Boost: Dalvik JIT によって、Android 2.1 に比べて、CPU-heavy code が 2~5倍パフォーマンスがスピードアップしました。

Kernel Memory Management Boost: メモリの再利用が最大20倍改善しました。つまり、デバイスにメモリが制約される状況で、アプリの切り替えがより速く、パフォーマンスがスムーズになりました。






New Platform Technologies

Media framework
・新しいメディアフレームワーク(Stagefright)は、ローカルファイルの再生とHTTPストリーミングをサポートしています
・Android 2.2 でも OpenCoreのサポートは継続します

Bluetooth
・Bluetooth からの音声ダイアル
・他の携帯電話とコンタクトを共有できる
・車およびデスクドックで Bluetooth を有効にするためのサポート
・カーキットやヘッドセットとの互換性の向上

2.6.32 kernel upgrade
・RAM >256MB に対して HIGHMEM をサポート
・SDIO スケジューリング と BT の改善




New Developer Services

Android Cloud to Device Messaging
アプリは Device Messaging に Android クラウドを利用することができます。
これにより、端末アラート、携帯電話への送信、双方向のプッシュ同期機能が可能になります。

Android Application Error Reports
Androidマーケットアプリケーションのための新しいバグレポート機能によって、開発者がユーザーからクラッシュやフリーズのレポートを受け取ることができます。レポートはデベロッパーコンソールで確認できます。




New Developer APIs

Apps on external storage
共有外部メモリ(例えば SD card)からアプリケーションをインストールできる

Media framework
新しいAPIは、オーディオフォーカス、SCOへのオーディオルーティング、およびファイルのメディアデータベースへの自動スキャンを提供します。
また、アプリケーションが、サウンドの読み込み、自動停止、自動プレイバックによる再開を検出できるようなAPIを提供します。

Camera and Camcorder
新しいプレビューAPIはフレームレートを2倍(~10FPSから~20FPSへ)にします。
カメラは、縦向き(portrait)、ズームコントロール、露出データへのアクセス、サムネイル設定をサポートしています。
新しいビデオカメラのプロファイルは、アプリケーションがデバイスのハードウェア能力を決定することを可能にします。

Graphics
OpenGL ES 2.0 の新しい API は YUV画像形式、および ETC1 のテクスチャ圧縮で動作します。

Data backup
アプリのデータがバックアップおよび復元できるようになりました。
ユーザーがファクトリーリセットを実行した後や、デバイスを切り替えた後も、
データが維持されます。

Device policy manager
新しいデバイスのポリシー管理APIによって、開発者は"デバイス管理"アプリケーション作成することができます。
これは、デバイス上のセキュリティ機能(例えば、最小パスワード強度やデータワイプなど)を制御できます。
ユーザーは自分のデバイスで有効になっている管理者を選択することができます。

UI framework
新しい"car mode"と"night mode"のコントロールと設定は、アプリケーションがこのような状況のためにUIを調整することを可能にします。
スケールジェスチャー検出APIは、改善されたマルチタッチのイベントの定義を提供します。
アプリケーションは、TabWidget の下部にあるストリップ(bottom strip)をカスタマイズできます。



新しい developer APIs のより詳しい情報は
Android 2.2 version notes
API Differences Report
を見てください。

'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,''):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

Blogger Syntax Highliter

Version: {V}

http://www.dreamprojections.com/syntaxhighlighter

©2004-2007 Alex Gorbatchev.

'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,'\n'):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

ページビューの合計