2012年11月26日月曜日

WebViewでvideoタグのページを閲覧する

現在HTML5関連のお勉強をしています。
スマートフォンの端末やブラウザソフト毎に対応がバラバラなのがネックですね…。
というわけで、今回の話題はHTML5から動画ファイルの再生を容易にしたvideoタグについて。

ためしに
 <video width="***" height="***" autoplay loop>
 <source src="../movie/movie.mp4"></source>
 <source src="../movie/movie.webm"></source>
 </video>
こんな感じのタグを埋め込んだHTMLファイルをサーバに置き、
Android端末から色々なブラウザで閲覧してみました。

Android(docomo GalaxyNexus OS_4.1.1)
 ・Android標準ブラウザ 4.1.1 ⇒ ○ 
 ・FireFox 17.0 ⇒ ○
 ・Chrome 18.0.1025464 ⇒ ○
オプションの有効無効などの多少の差異はありましたが
ブラウザアプリを立ち上げて見る分には問題無い事を確認。


…で、問題が、AndroidのWebView、でした。


AndroidのWebViewでVideoタグを見ようとすると、
プレイヤーは表示されるのですが再生ボタンを押しても何も表示されない。
カーソルだけが動く、でもそのカーソルも操作しようとすると
謎の挙動を起こす、そして表示は相変わらず何も起こらない。
そんな感じでした。

そんな馬鹿な!!と、なんとかAndroidWebViewでvideoタグを閲覧する方法をググらせて頂くと
ちゃーんと用意してくださっている方がいらっしゃる。ありがたやありがたや…
http://code.google.com/p/html5webview/
http://www.tandroid.org/html5webview

1.ココ
 「Source」タブに記載されているリポジトリからSVNを用いてソースコードを頂く
 ソースコードはhtml5WebViewを用いたサンプルプロジェクトになっている

2.自分のプロジェクトを作成するなりなんなりする
 忘れない内にAndroidManifest.xmlファイルにInternetのパーミッションを指定しておく

3.先程頂いたプロジェクトファイルから複製する
 ・srcの…HTML5WebView.java
 ・リソースフォルダの…
  drawable/default_video_poster.png
  layout/custom_screen.xmlとvideo_loading_progress.xml
  value/colors.xmlとstrings.xml(既に作成されていたらマージする)

4.あとはWebViewを用いるところをHTML5WebViewで作成する
 HTML5WebViewインスタンスの生成はこんな感じで
 HTML5WebView webView ⇒ webView = new HTML5WebView(this)
 (基本サンプル様のやり方をまねればOK!!)

これで動く…はず!!


おまけ:
 上記の方法で普通は動くけれども、
 私の場合はおまけで以下のようなエラーが発生したのでメモです。

Caused by: java.lang.IllegalStateException: The specified child already has a parent.
You must call removeView() on the child's parent first.


HTML5WebViewインスタンスをLinearLayoutに埋め込もうとしたのですが
当のHTML5WebViewインスタンスが
「既に親のオブジェクトを持ってしまっているので、
指定のオブジェクト(今回の場合はLinearLayout)を親にする事が出来ません。
現在の親オブジェクトの指定を取り除いてください」という事らしいです。

ViewGroup parent = (ViewGroup)webView.getParent(); 
if ( parent != null ) { //webViewの親グループを削除しておく
parent.removeView(webView);
}

こんな感じに親オブジェクト(グループ)を削除。
無事、指定のLinearLayoutにaddView()で挿入する事ができましたv
(参照サイト様:http://d.hatena.ne.jp/Kazzz/20100603/p1)

2012年11月1日木曜日

リンゴさんに文句言いたくなるわ。

役に立つか分からないメモ、というより愚痴です。
愚痴、いいたくなりますよ。リンゴさん。

[事のいきさつ=結構どうでもいい]
つい先日からiPhoneの方で物作り、というほどでもないのですが、やり始めまして。
開発PCのOSのバージョンが古かったんです。雪豹ちゃんです。
既存のアプリをこの雪豹ちゃんでいじろうとしましたが、
その既存アプリはもともと山獅子ちゃんで作られていて、xCodeのバージョンも違う。
だからなのか、いじれないなぁ…となりまして。
じゃあ、雪豹ちゃんを山獅子に進化?させてやりましょう、と。
[回想終了]

さて、ここからアンサイクロペディアの「たらいまわし」のごとき
ぐぐる先生をさまよう旅がはじまりました。

まずは自分のAppleIDを作らねば、と作りに行きました。
日本語のまま、ね。
名前も、住所も全てジャパニーズでしっかり登録(フラグ)

はいじゃあ作りましたという事で、次にディベロッパー登録せねばとね。登録しました。
よし、じゃあまずは普通にライオンちゃんに来てもらうかね、とライオンちゃんをクリック。

「あなたのAppleID、iTunesで使われた事ないね。レビュー見てね」
見たいな事言われて、あぁはいすみませんとレビューへ。

iTunesアカウント作ろうとしたらそこで一悶着あったんですけど、忘れました。
(登録できないーって何か暴れていた気がします…何が起こってどうやって解決したやら…)
クレジットカード登録を避ける方法ですが、
一般的な方法(無料アプリを落とす時のアカウント作成画面を利用する)は
既にAppleID作っちゃってたからか出来ませんでした出来ませんよね?
というわけで一旦カード情報登録して、即行で削除しました。面倒クセェ
四苦八苦してなんとかiTunesアカウントゲット。

よしよしじゃあライオンちゃんいらっしゃい、とライオンちゃん購入。
AppleStoreの購入一覧にかわいいライオンちゃんがいたのでクリック、すると…
「この商品、日本じゃサポートしてないよ?」的なメッセージ。
…………は?(゜Д゜#)
いやいや何血迷った事言ってくれるのさ、そんなわきゃねぇだろ、と
AppleIDか、はたまたiTunesアカウントが悪さしているのか。

この理不尽なメッセージは海外の商品を購入する際によく出るメッセージだそうで。
いや、でも、これOS…
とりあえず、iTunesアカウントの国籍を一旦米国にさせていただくかな、と変えようとしたら
「このアカウント、日本じゃねーと使えねぇから!!(お前席ねぇから風」って突き放されちゃいまして。
え、じゃあAppleIDは?とためしにやったら、
こっちはこっちで「無理。あんたの時計が狂ってるか、Appleのクッキー有効にしろや」と怒られた。え、意味分からん。

~ここで半日程無駄にする~

上記のような意味不明状況の解決方法。

AppleStoreで無料のソフトを落とす。

(ここでも雪豹ちゃんが古いせいで「バージョン古いwwwごめん対象外だわwww」って
はじかれまくった。対象スペックの欄が見つからないんですって…)
その時に3つの魔法の言葉ならぬ質問と、
AppleIDに登録したのとは別のメアドを登録ってページになってぽちぽち記入、進む。

そしたら。急に、ライオンちゃんのダウンロードが開始してた。

…(゜Д゜)

…(゜Д゜)

?(゜Д゜)

何事もなかったかのようにダウンロードを終えて、ついでに無料ソフトもばっちり入ってました。
……………………………………………………………
…………………………えぇえええぇえええ!!?
何、が、起こったし…わけがわからない。


そして最初の死亡フラグ、AppleID作成時に日本語入力した項目が
ばっちりバグっとります(現在進行形)
「日本語で登録すると名前が修正できなくなって、厄介な事になるよ!!」と
ぐぐる先生回っている最中に知ったので「え」となって
あわてて修正しにいったのですが時既に遅し。

メンバーページに行くと「Hi,(日本語名前)(英語姓)」となる。
…名前が日本語のままになって直らないらしいですね…
MyInfoってページで直せるという噂があったのですが繋がりませんでした。
これからAppleID作られる方は御気をつけて…。

2012年10月17日水曜日

TabHostのタブを1つだけ削除する

【目的】TabHost>TabWidget内のタブを一つだけ削除したい
(TabHost.clearAllTabs()による全タブ削除じゃなくて)
(実装環境:GalaxyNexus ver_4.0.4)

調べ方が悪かったのか、なかなか見つかりませんでした…
しかも解決策として採用したのが2008年の見知らぬ海外の掲示板でのやりとりという…
(参照先URL:http://www.coderanch.com/t/460859/Android/Mobile/TabHost-Remove-Tab)
もっと正規の方法があるかもしれませんが、一応メモです。

<タブ削除の為の下準備>
1.TabHost.TabSpecのListを作成しておく
 List<TabHost.TabSpec> tabSpecs = new ArrayList<TabHost.TabSpec>();

2.タブ追加時に生成したTabHost.TabSpecインスタンスをListに格納しておく
 TabHost.TabSpec tabSpec = new tabHost.newTabSpec([TabId]).setIndicator(...);
 tabHost.addTab(tabSpec);
 tabSpecs.add(tabSpec);

<タブ削除の手順>
3.Listから削除したいタブに相当するTabHost.TabSpecを削除する
 tabSpecs.remove([index]);

4.タブを一度、全削除する
 tabHost.clearAllTabs();

5.Listを利用して、再度タブを生成する
 for(TabHost.TabSpec ts : tabSpecs){
  tabHost.addTab(ts);
 }

これで、おそらくタブを一つだけ削除した状態になる…かと…
でもこれってメモリの食い具合ってどうなるのでしょう…
捨てたつもりが実は捨ててないとか、ありそう、うぅん…


ちなみにわたしは諸事情により、TabHost.addTab(...)以降に
動的にタブのラベルやアイコンを変更したりしていたのですが
上記の手順では一旦全部のタブを消去して、タブを作り直してしまっているので
それらの変更もきれいさっぱりなくなっちゃいました…
なのでその辺の対応もしなくてはならなくなり、正直面倒くs…ゲフンゲフン。

2012年5月23日水曜日

XMLParseに失敗しちゃう

WebAPIからXMLを取得して解析しようとしたら
以下のようなエラーが発生しちゃいました。

org.xmlpull.v1.XmlPullParserException: END_TAG expected (position:START_TAG <item> //…(以下略)

特定のスタートタグ(以下の例"target")でnextText()メソッドを用いて取得しようとしたのですが、
このnextText()がダメだったようです。
(参考サイト様:http://yome9.blogspot.jp/2012/03/xmlpullparserxml.html)

while(true){
 eventType = parser.next();

 if(eventType == XmlPullParser.START_TAG
  && "target".equals(startTag)){
  text = parser.nextText();
 }
}

(例)
<nesting>
 <target>...</target>
</nesting>
XmlPullParserが<nesting>を指してるときにnextTextを取得しようとすると、
次がタグ(<target>)になってしまうのがまずいのでしょうか…?

しかし、取得元のXMLを見る限りだと私が欲しい情報は最も入れ子になっている要素なので
上記の条件には当てはまらないはずなのですよ…うーん、わからない…。
それとも事前に上記のようなことが起こらないようにエラーを吐くようにしてるのでしょうか。

うーん、見当違いな事書いているような…下手に自論をひねり出そうとするからですね。
反省反省…。もうちょっと確証もてるような事が浮かんだら書き直そう。


仕方ないので以下のように変更して回避しましたー

while(true){
 if(eventType == XmlPullParser.START_TAG){
  String startTag = parser.getName();
  if("telop".equals(startTag)) getText = true;
 }
 else if(getText && eventType == XmlPullParser.TEXT){
  text = parser.getText();
  getText = false;
  break;
 }
}

ううん…要調査です。

2012年5月18日金曜日

作りたいよライブ壁紙

ライブ壁紙を作りたいので計画をメモしていく。

【作りたいもの】天気予報に連動したライブ壁紙(ペ●ソナ4の天気予報風)
・天気情報を取得できるAPIから天気予報を取得して表示させると同時に、
天気・日付に連動したアニメーションを入れる。
・もしも情報を取得できない場合は天気予報の欄は全部曇り(霧)とし、
情報取得失敗を表すアニメーションを入れる。
⇒霧条件:WiFiがONになってない/HTTPのGET失敗
・ライブ壁紙の設定によってノーマル/マガツバージョンに切り替えられる

作る宣言、大事。

2012年4月13日金曜日

Uri.parse(...)でリソースフォルダを参照したい【メモ】

【目的】ノテフィケーションの通知で鳴らす音源をリソースフォルダ内に置いて、使用したい
【分からなかった事】Uri.parseメソッドのURIの書き方
(実装環境:GalaxyNexus OS_ver.4.0.2)

例)ノティフィケーションの通知音を指定する時
(リソースは res/raw/bell.ogg に配置)

notification.sound = Uri.parse("android.resource://com.package/raw/bell");

【結論】UriString="android.resource://" + <パッケージ名> + "/" + <リソースフォルダ下のパス>
(参照先:http://stackoverflow.com/questions/5373212/uri-parse-to-res-folder)


ファイル構造をちゃんと理解していないからですよね…ハハッ(苦笑
検索しても中々引っかからなかったので、あまりこのような事をする方がいらっしゃらないのか
はたまた常識中の常識なのか、わかりませんが、私は分からなかったわけで…メモ。

検索していて"//"が無い方とか、パスの最後を「R.raw.bell(←intのまま)」と
いった感じの方がいらっしゃいましたが、うまくいきませんでした。
バージョンとかの違い…ではなさそうなのですが…

※※※ 追記 ※※※
上記のパスでVideoViewのファイルを参照しようとしたら
「この動画は再生できません」というエラーが出てしまいました。
しかし、端末の方に事前に動画ファイルを入れて
Uri.parse("/data/…");
で指定した所あっさり再生できちゃいました…

…どういうことだってばよ…orz

2012年3月29日木曜日

GalaxyNexusと802.11a【メモ】

【目的】GalaxyNexus(OS_ver.4.0.2)で802.11aに設定した複数台のアクセスポイントの電波強度を測定したい
【現象】WiFiアクセスポイント一覧にアクセスポイントが全部表示されない(検知されない)

諸事情により、5GHz帯しか使用できないという前提条件でGalaxyNexusを使おうとしたら、一部アクセスポイントが検知されないという現象が発生しました。
アクセスポイントは全部で6台あり、学校のプールほどもないスペースに全て配置するという若干特殊な環境でした。
検知される・されないアクセスポイントはその時その時で異なり、アクセスポイントの個体差による問題ではないということは確認しました。
チャンネル重複による電波干渉が原因かな…と思いましたが、どうも様子が違う…。
検知されない固体は暫くずっと検知されないのです。


で、検証によりGalaxyNexusさんは802.11a中のW52(チャンネル36~48)しか使えない、と結論付けました。某掲示板でもそのようにおっしゃってる方がいらっしゃったので、まぁ…皆さんもそういうことなのかな…と。

チャンネルの選択を自動にしていたのですが、W52以外を選択したアクセスポイントだけが検知できないという感じでした…W56はともかく、W53についてはバグなのでしょうか?それとも現段階での仕様なのでしょうか?
GalaxySⅡ(OS_ver.2.3.6)でも検証したところ、こちらはW52/W53共に検知できました。


4.0.1の時はそもそも802.11aは未対応との事でしたので、本件についてもすぐ改善されます、かね…?

2012年1月26日木曜日

再生・逆再生するようにムービークリップを制御(メモ)

対象のインスタンスにEvent.ENTER_FRAMEのイベントリスナーを登録


mc1.addEventListener(Event.ENTER_FRAME, everyFrame);

var rePlay:Boolean = false;
var reCount:uint = 0;

function everyFrame(event:Event):void
{
if(rePlay){
if (event.currentTarget.currentFrame == 1)
{
if(reCount>=1){
reCount = 0;
rePlay = false;
}else{
reCount++;
}
}
else
{
event.currentTarget.prevFrame();
}
}else{
if (event.currentTarget.currentFrame == event.currentTarget.totalFrames)
{
if(reCount>=15){
// 15フレーム停止
reCount = 0;
rePlay = true;
}else{
reCount++;
}
}
else
{
event.currentTarget.nextFrame();
}
}
}




…こういうコード表示がしてみたかっただけという…
http://gogotorotan.blogspot.com/2011/03/syntaxhighlighter.html
とってもお世話になりました。