2012年10月30日火曜日

Nexus 7(32GB)の日本での販売開始。Nexus 10は11月13日から。Nexus 4は日本販売予定なし。

Nexus 4, 7, 10が発表された。ハリケーン「サンディ」上陸の影響で発表会が開けなくて、Googleは残念だったろう。

以下は発表された販売スケジュール。ちなみに、Nexus 4とNexus 7(32GB)3G対応モデルの、日本での販売予定は今のところ無い



どちらもOSは4.2(Jelly Bean)。

8GBは$299、16GBは$349。米国、英国、オーストラリア、フランス、ドイツ、スペイン、カナダのGoogle Play Storeで11月13日から販売開始。

Nexus 4はLTEが使えないのがミソ。



OSは4.1(Jelly Bean)。

16GBのWiFiモデルは、既に日本でも販売されているが、今日から32GB WiFiモデルの販売も始まった。価格は24,800円


Nexus 7(32GB)3G対応モデル by ASUS

OSは4.1(Jelly Bean)。

$299でアンロックされて販売される。米国、英国、オーストラリア、フランス、ドイツ、スペイン、カナダのGoogle Play Storeで11月13日から販売開始。



どちらもOSは4.2(Jelly Bean)。

16GBは36,800円、32GBは44,800円で、11月13日から日本で販売開始。その他、米国、英国、オーストラリア、フランス、ドイツ、スペイン、カナダのGoogle Play Storeでも11月13日から販売開始。

Android 4.2(Jelly Bean)の特徴まとめ

Android 4.2搭載のNexus 4, 7, 10が発表された。そこで、4.2で新しく加わった機能などをを少しまとめてみた。


・コードネームはJelly Beanのまま

4.1から変わらないのね。


・Photo SphereでJPEG画像がストリートビューのように見られる

今回のOSで一番売りにしているポイントっぽい。

JPEG画像のメタデータの中にXMLを含めることで、静止画像なのに上下左右など、撮影した画像の周辺が360度見られる。
Hugo Barra - Google+ - Photo Sphere: capturing the world around you We just…

4.2でJPEG画像を開けば、なんでもそのように見られるわけではなく、4.2搭載の端末のカメラで撮影した画像のみ対応する。


・ユーザーの切り替えができるようになった(タブレット限定機能)

MacやWindowsなどのデスクトップOSのように、マルチユーザーで1端末が使用される、ホームユースを考えて搭載した機能だろうね。

ユーザー毎に領域が分けられているので、ホームスクリーン、壁紙、ウィジェット、アプリ、ゲームのハイスコアなども、個人ごとに管理される。ログアウトせずに、別のユーザーに切り替えることも可能。

これはタブレット限定の機能で、4.2搭載でもフォンタイプではこの機能は使えないみたい。


・フォンからタブレットへ動画や写真をワイアレスで映し出す

動画や画像をもうちょっと大きく見たいという時に、HDMI対応のTVや4.2搭載タブレットへダイレクトで表示内容を映し出すことが出来る。

家族が集った時や結婚式などのイベントで有効に使えるかも?


その他の情報は Android - What's New で確認できる。

2012年10月29日月曜日

YouTube動画をダウンロード可能にする機能はTOS違反。・・・だよね?

YouTubeの動画をダウンロードさせるアプリケーションがApp Store等で幾つも公開されている。中には有料のアプリだってある。これってアリなの?と普段から気になっていたので調べてみた。


Terms of Service - YouTube — Google Developers

I. API Use
Compliance with Terms.
You may use the YouTube API, and the data, content, and information made available through the YouTube API ("API Data"), in connection with a website or software application ("API Client") developed by You only in accordance with the terms and conditions of this Agreement, the YouTube Terms of Service (currently located at http://www.youtube.com/t/terms), the YouTube API documentation and specifications (currently located at http://code.google.com/apis/youtube/overview.html), and the developer credentials and API Client IDs assigned to you by YouTube.


「開発したWebサイトやアプリケーションで、YouTube APIを通してデータ、コンテンツなどの情報を扱いたい場合は、YouTubeの利用規約、YouTube APIのドキュメント・仕様、開発者証明、YouTubeのAPI Client ID(YouTubeによって割り当てられたID)への合意によってのみ使用を許可される。」意訳するとこんな感じか。


そして、YouTubeの利用規約の「5. お客様によるサイト上のコンテンツの使用」の項目Bには、ダウンロードを許可しない記述がある。

本コンテンツは、「現状有姿」でお客様に提供されています。お客様は、本コンテンツに、本サービスの機能により意図されており本サービス条件により認められている限度で、参考目的での個人的な利用のためにのみアクセスすることができます。お客様は、「ダウンロード」または同様のリンクが本コンテンツについて本サービス上でYouTubeにより表示されている場合を除き、いかなる本コンテンツもダウンロードしてはなりません。

「本サービス上でYouTubeにより表示されている場合」はダウンロードはOK、ダウンローダーのようなソフトウェアのダウンロードリンクはダメ、という所まで書いてある。動画のオーナーだったら自分がアップした動画にはダウンロードボタンが付いているが、それのみOKということだろう。


ダメ押しで、FAQにもちゃんと書いてある。

YouTube 動画をダウンロードできますか?

いいえ。YouTube 動画をサイトからダウンロードまたはそれを試みるサービスを提供しているウェブサイトは数多くあります。しかし、コンテンツの提供時に YouTube によって「ダウンロード」リンクまたはそれに類似するリンクが表示されている場合を除き、YouTube 動画をダウンロードすることや外部のアプリケーションを使用して動画をダウンロードすることは、動画所有者の著作権を侵害し YouTube の利用規約に違反する行為です。


やっぱり、YouTube動画をダウンロード可能にする機能はYouTubeのTOS違反だ。

でも、そんなアプリでもApp Store等の審査で弾かれないのが不思議。

App Store等にしてみれば、自らのTOSを遵守しているかは確認するが、そのアプリが利用しているAPIまでの遵守確認は行わない、そこまでは知ーらない、ということか。


ダウンロードできると便利なシーンはいろいろあるが・・・。でもTOSに反するようなアプリをユーザーさんには使わせられない。

自分がアプリを作るときにはTOSに反しないように意識しておく。

2012年10月27日土曜日

GCMのIntentServiceでAsyncTaskを実行したらsending message to a Handler on a dead threadの警告が出て悩まされる

GCMサーバーからメッセージが送られてきた時の処理をGCMIntentServiceのonMessage()へ記述している。
my.app.GCMIntentService
  |- com.google.android.gcm.GCMBaseIntentService
      |- android.app.IntentService

onMessage()内でAsyncTaskクラスを作成してexecute()したところ、以下のようなWarningが出た。
10-26 15:24:14.025: W/MessageQueue(482): Handler{44f63ea8} sending message to a Handler on a dead thread
10-26 15:24:14.025: W/MessageQueue(482): java.lang.RuntimeException: Handler{44f63ea8} sending message to a Handler on a dead thread
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:179)
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.Handler.sendMessageAtTime(Handler.java:457)
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.Handler.sendMessageDelayed(Handler.java:430)
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.Handler.sendMessage(Handler.java:367)
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.Message.sendToTarget(Message.java:348)
10-26 15:24:14.025: W/MessageQueue(482):  at android.os.AsyncTask$3.done(AsyncTask.java:214)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.FutureTask$Sync.innerSet(FutureTask.java:252)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.FutureTask.set(FutureTask.java:112)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:310)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.FutureTask.run(FutureTask.java:137)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
10-26 15:24:14.025: W/MessageQueue(482):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
10-26 15:24:14.025: W/MessageQueue(482):  at java.lang.Thread.run(Thread.java:1096)

コードのスニペット。
@Override
 protected void onMessage(final Context context, Intent intent) {
  Log.i(TAG, "Received message.");
  // IMAGE_IDを取得
  String imgId = intent.getStringExtra(IMAGE_ID);
  
  // Async version
   GetImgTaskTest getImgTaskTest = new
   GetImgTaskTest(context.getApplicationContext());
   getImgTaskTest.execute(imgId, null, null);
 }


StackOverFlowで、このWarningの回避策が触れられていた。

Issue 20915 - android - AsyncTask can get initialized with wrong Looper - Android - An Open Handset Alliance Project - Google Project Hosting

そこでは、onCreate()内でAsyncTaskクラスをロードしておくやり方が紹介されていた。
public class YourApplication extends Application {

    @Override
    public void onCreate() {

        // workaround for http://code.google.com/p/android/issues/detail?id=20915
        try {
            Class.forName("android.os.AsyncTask");
        } catch (ClassNotFoundException e) {
        }

        super.onCreate();
    }
}


これはAsyncTaskクラスのバグだという言及も。

android - onPostExecute not being called in AsyncTask (Handler runtime exception) - Stack Overflow

This is due to a bug in AsyncTask in the Android framework. AsyncTask.java has the following code:

private static final InternalHandler sHandler = new InternalHandler();

It expects this to be initialized on the main thread, but that is not guaranteed since it will be initialized on whichever thread happens to cause the class to run its static initializers. I reproduced this issue where the Handler references a worker thread.


しかし、このClass.forName()を使う方法は、あまりエレガントに思えなかったので、AsyncTaskのスレッドルールについて調べてみた。

AsyncTask | Android Developers "Threading rules" より
・The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
・execute(Params...) must be invoked on the UI thread.

AsyncTaskのAPIドキュメントにも、UI threadでクラスをロードせよ、execute()はUI threadで実行せよと、しっかり書いてある。


ナゼ?


まず基本的なことから。


・AndroidのUIは基本的にsingle threadモデルであることを理解すべし

AndroidのUIは基本的にsingle threadモデル。全てのアプリは1つのプロセスとスレッドで実行される。そのスレッドのことを別名"main" threadとよんでいる。

UI threadの中で、ネットワーク通信やデータベース検索など、時間がかかる処理を実行した場合、レスポンスが悪くなったり、アプリが止まっているように見えたりしてしまう。よって、以下の2点だけは守ろう。

Processes and Threads | Android Developers "Threads"より
Thus, there are simply two rules to Android's single thread model:

1. Do not block the UI thread
2. Do not access the Android UI toolkit from outside the UI thread


・時間がかかる処理はworker threadで行い、main threadから分けるべし

即座に応答しなくてよい操作だったら、それらは別のスレッド(バックグラウンドやworker threads)で処理できないか確認しよう。

Processes and Threads | Android Developers "Worker threads"より
If you have operations to perform that are not instantaneous, you should make sure to do them in separate threads ("background" or "worker" threads).

で、worker threadの結果は、以下の様なメソッドやクラスを使って反映させよう。



分かった!Warningの理由

そう、つまり、AsyncTaskは、worker threadがUI threadとコミュニケートしながら処理を進めるという操作を、簡単に書けるように作られたクラスなのだ。だから、execute()はUI thread内で実行することを想定している。

AsyncTaskのClass Overviewにも、真っ先に書いてある。

「AsyncTaskはUI threadを適切に、そして簡単に使えるようにしたもの。このクラスを使うと、ThreadやHandlerを使って自分で色々せずに、処理をバックグラウンドで行い、その結果をUI threadへ表示させることができる。」
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread.


ここまで整理すると、Warningが出ていた理由も理解できる。

UI threadで実行するルールになっているAsyncTaskを、IntentService内で、つまりworker thread内でexecute()したていたからだ。

IntentSreviceではAsyncTaskは使えない。

非同期処理と思うとAsyncTaskと直ぐに思ってしまうけれど、常に使える手ではないということだろう。


じゃ、どうするか。


そもそもやりたかった処理は、メッセージを受信したら画像をダウンロードするというもの。その際Activityは起動しない、Notificationのみ表示する。onMessage()はその処理をキックするだけ。

ムム〜。やっぱりThraed回すのが手堅そう。となると、java.uti.concurrent.Executor あたりにヒントがありそう。