投稿

MediaPlayer + Proxy で気を付けること

暗号化された楽曲ファイルを複合化しながら再生しようとした場合、 MediaPlayerとファイル間にProxyをはさんでやるのはよく見かける方法だと思います。 しかし、MediaPlayerはRangeRequestを送ってくる(端末がある)ので、 Proxyはそれに対応出来ようにしておかないとえらい目にあいます。 ちなみにRangeRequestを送ってくるMediaPlayerですが、 手元にある端末ではNexus7(OS5.0)からこの動きになっています。 具体的に、まずリクエスト読み込み部分でRangeタグの有無をチェックしましょう。 InputStream is = client.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is), 2048); String line; while (!TextUtils.isEmpty((line = reader.readLine()))) {   if (line.contains("Range:")) {     String[] rangetag = (line.split("="))[1].split("-");     mRangeRequest = Long.parseLong(rangetag[0]);   }   result.append(line); } そんでもってレスポンスを返す部分で、 String headers = ""; long length = dataSource.getContentLength();  // コンテンツサイズ String mime = dataSource.getContentType();// コンテンツタイプ if (mRangeRequest > 0) {   headers += "HTTP/1.1 206 Partial Content\r\n";   headers += "Content-Type: " + mime + "\r\n...

in app billing v3 でサンドボックステストするときの話

とりあえずサンプルアプリのコードをちょちょっといじって、おなじみの"android.test.purchased"を買おうとすると、購入後のセキュリティのチェックでエラーが出てめんどうなことに。 E/IABUtil/Security(5973): Purchase verification failed: missing data. E/IabHelper(5973): In-app billing error: Purchase signature verification FAILED for sku android.test.purchased どうもSecurity.javaに問題があるようで、"android.test.purchased"を購入しようとするとSecurity#verifyPurchaseでsignatureがnullとなりエラーシーケンスに移行するご様子。 そしてここでエラーが起きると、その後のconsumePurchaseを呼び出す処理に到達しないため、結果としてアイテムが二度と買えない羽目に・・・。 この状態になるとアプリをアンインストールしても元の状態に戻せません(GooglePlayの方で購入情報をキャッシュしているので)。 アプリ設定からGooglePlayのデータを消去してやることで一応復旧はするみたいです(一部アカウント情報なんかが消えた気がしますが・・・)。 で、下記の参考サイトをもとにsignatureがnullの場合もtrueを返すように修正して動作するように修正しまんた。 if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || TextUtils.isEmpty(signature)) {         Log.e(TAG, "Purchase verification failed: missing data.");           if (BuildConfig.DEBUG) {                 ...

Eclipseで既存ソースコードを読み込もうとしたときに怒られる話

大変参考になりまんた。 http://d.hatena.ne.jp/ekrea/20110214/1297670097

こまめにBlogを書くなんて

はなから無理な話でした。 --- キリトリ --- Viewの描画のお話。 Viewのサイズを取得(getWidthとか)する際、まだ画面上にViewが描画されていないと 0 が返されます。 Activity上であれば、onWindowFocusChanged()が呼び出される時には確実にViewが描画されているので、 このタイミングでサイズを取得すればよいのですが、サイズの取得をActivity以外で行いたいときに、 今まではメソッドなどを通じてわざわざActivityから呼び出しを行っていました。 そんな面倒なことをしなくともViewTreeObserverを使えば、Viewを保持しているクラス内で完結出来るのです、すごい! お勉強させていただいたサイト様 @blog.justoneplanet.info

@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree

っていうエラーのお話し。 開発したアプリのテストをしていると、ある処理を行うところでアプリがkillされる現象に陥った。 ぱっとみメモリ不足ではなさそうだったので頭をひねっていると、 プロセスがkillされる直前に以下のようなエラーが出ていることに気付く。 03-05 16:15:06.762: A/libc(19768): @@@ ABORTING: INVALID HEAP ADDRESS IN dlfree 03-05 16:15:06.782: A/libc(19768): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1) いかにもネイティブのエラーですって顔してて嫌な感じだったので、 いつも通りStackOverflowを頼るときれいな回答が。 What it boiled down to is a function call being made from two different threads at the same time. More specifically, this function was BluetoothSocket's close() method. I checked the source code  at this website  , and the call is not synchronized (not sure if this changed since it is from Android 2.1). 引用元: http://stackoverflow.com/questions/10662446/invalid-heap-address-and-fatal-signal-11(StackOverflow) どうも異なるスレッドから同時にメソッドを呼び出すと発生するご様子。 何でsynchronizedされていないのかは分からないけど、 思いっきりBluetoothSocket#close()を使っていたので排他的に呼ばれるように修正。

Bitmapオブジェクトをbyte配列に

日曜なのに会社。 びっくりするほどの社畜生っぷり、くそがー。 ByteArrayOutputStream bos = new ByteArrayOutputStream(); // ByteArrayOutputStreamオブジェクトを作り bmp.compress(CompressFormat.JPEG, 100, bos); // Bitmapオブジェクトを圧縮してストリームに流し込み byte[] bmpAry = bos.toByteArray(); // ストリームをバイト配列にする 引用: http://d.hatena.ne.jp/hyoromo/20091219/1261232755

Activity以外からstartActivityする

Androidは覚えきれないから得られた情報は書き残しておこうと心に誓ったのに、 なんで前回のポストから3ヵ月も経っているの・・・? 仕事中にBloggerを開く癖をつけるか。 いっそメモ書きしたらBloggerにポストされるように出来ないかな。 タイトルここから Activity以外(のContext)からstartAvtivity()を呼び出すと以下のエラーが発生する。 android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want? なのでserviceなんかから呼び出す場合はFLAG_ACTIVITY_NEW_TASKをセットしてやる必要がある。 Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 理由は後ほど調べる。