2011年9月30日金曜日

Sharp ハッカソンで作ったアプリを公開しました。

子供向けのホームアプリ(正確には、自分が普段使っているスマホでときどき子供にゲームとかさせる親向け)です。

Pakaroid - Android Market

「子供にスマートフォンのアプリで遊ばせたいけど、関係ないアプリを勝手に起動させたくない。」
「子供用のアプリに簡単にアクセスしたい。」
「子供でも使えるようなホームアプリに、アプリをまとめておきたい。」

そのためにどういうアプリがいいかな、ということで、

・ホームから子供が自分でアプリを起動できる

  - Pakaroid(パカロイド)というゆるキャラをタップして
   アプリ一覧を表示(しかもキャラがでかいからタップしやすい)
  - 全体的にポップな感じ
  - アニメーションをつけて楽しく

・関係ない操作をさせない

  - メニューキーのロングタップや検索キーのロングタップを無効化
  - 設定アプリなどへの入口であるダイアログの表示方法を
    メニューキーをタップ
    メニューキーをロングタップ
    メニューキーをタップしながらボリュームアップボタンを押す
  から選択できる
  (メニューキーをタップしながらボリュームアップボタンを押す、なら
   知らなければ子供が誤って押しちゃうことはまずないだろうと)

  - もし誤ってダイアログを表示しちゃっても10秒で自動的に
   ダイアログを閉じる

・関係ないアプリを起動させない

  - 選択したアプリだけを一覧に表示

などの機能をいれました。

他にも

 - バッテリーの残量に応じて草の量が変わる
 - 充電ケーブルをつなぐと雨が降るなど

など、ちょっとしたところに凝ってます。





ぜひ使ってみてください!

Team Pakaroid のメンバーです。
- Yuki Anzai (@yanzm)
- Rin Yano (@yanorin)
- Kazuya Matsubara (@Toro_kun)
- Masahide Fukagawa (@PUKa)


---

ここからは広島旅行の思い出ということで。
7月23日

飛行機にのって

空港からバスで白市駅まで行き、

白市駅から電車で八本松駅まで行き、
八本松駅からタクシーで工場まで行きました。
タクシーの運転手さんの話だと、昔、枝が八本あるように見える松があったから八本松駅なんだそうです。(でもちょっと記憶があいまい、、、)

1階に携帯電話の展示コーナーがあって、IS03 の三枚おろしみたいなのとかありました。
面白かった。

ハッカソンシールもらいました。

お弁当が豪華でした。おいしかったです。

ちーむぱかろいどのアイディアまとめとかの残骸

帰りの空港で時間があったので矢野さんと女二人でビール飲んできました。
ごちそうさまでした!



2011年9月21日水曜日

Android SharedPreference の実体ファイルの場所

ContextImpl.java をみると場所が書いてる 333 public File getSharedPrefsFile(String name) { 334 return makeFilename(getPreferencesDir(), name + ".xml"); 335 } 391 private File getPreferencesDir() { 392 synchronized (mSync) { 393 if (mPreferencesDir == null) { 394 mPreferencesDir = new File(getDataDirFile(), "shared_prefs"); 395 } 396 return mPreferencesDir; 397 } 398 } ということで、

 /data/data/[package_name]/shared_prefs/[name].xml

にあります。
エミュレータなら File Explorer や adb shell から見れます。

2011年9月20日火曜日

Android Scroll の終端のピカッを消す

Android 2.3 (Gingergread) からスクロールが終端までいくと、(デフォルトでは)オレンジ色にピカッと光ります。



これはこれでいいんですけど、デザインに合わないときもあります。



このピカッがどこで設定されているか調べると
AbsListView の setOverScrollMode() でした。
ここをみると、OverScrollMode が OVER_SCROLL_NEVER であれば、ピカッがなしになることがわかります。 650 public void setOverScrollMode(int mode) { 651 if (mode != OVER_SCROLL_NEVER) { 652 if (mEdgeGlowTop == null) { 653 final Resources res = getContext().getResources(); 654 final Drawable edge = res.getDrawable(R.drawable.overscroll_edge); 655 final Drawable glow = res.getDrawable(R.drawable.overscroll_glow); 656 mEdgeGlowTop = new EdgeGlow(edge, glow); 657 mEdgeGlowBottom = new EdgeGlow(edge, glow); 658 } 659 } else { 660 mEdgeGlowTop = null; 661 mEdgeGlowBottom = null; 662 } 663 super.setOverScrollMode(mode); 664 } ということで、ピカッとさせたくない場合は mListView.setOverScrollMode(View.OVER_SCROLL_NEVER); とすれば OK。

2011年9月15日木曜日

Android コードからステータスバーを開く

Launcher アプリにはステータスバーを開くメニューがある。

該当部分がこれ public static final String STATUS_BAR_SERVICE = "statusbar"; ... private void showNotifications() { final StatusBarManager statusBar = (StatusBarManager) getSystemService(STATUS_BAR_SERVICE); if (statusBar != null) { statusBar.expand(); } } StatusBarManager を使う。が、StatusBarManager は @hide である。

よって、これを使いたい場合の方法は、@hide を含む android.jar を使ってアプリを作る or リフレクションする。

例えばリフレクションするならこんな感じ private void showNotifications() { try { Object service = getSystemService("statusbar"); Class clazz = Class.forName("android.app.StatusBarManager"); Method method = clazz.getMethod("expand"); method.invoke(service); } catch (Exception e) { e.printStackTrace(); } }
ちなみに、AndroidManifest.xml で uses-permission に android.permission.EXPAND_STATUS_BAR が必要。

GWT で SimpleDateFormat がつかえない

java.text.* をサポートしてないらしい。

同じ機能の DateTimeFormat が用意されているので、こっちを使うべし。めもめも。

2011年9月11日日曜日

Android Menu の背景を変える その2

昔は Menu の背景を簡単に変えることができなかったんです。 それで Y.A.M の 雑記帳 Android Menu の背景を変える というエントリを書いたりしていたのですが、今は style から指定できるようになっているので紹介します。 <?xml version="1.0" encoding="utf-8"?> <resources> <style name="CustomTheme.Light" parent="@android:style/Theme.Light"> ... <!-- パネル(Menu) の背景 --> <item name="android:panelBackground">@color/menu_bg</item> <item name="android:panelFullBackground">@color/menu_bg</item> </style> ... </resources> のようにして、このテーマを AndroidManifest.xml の application や activity タグの android:theme 属性で指定すれば OK です。

ちなみに、できる限り style を使ってカスタマイズする勉強会を去年蒲郡でやりました。その資料にいろいろ書きましたので、ここにも貼っておきます。(Menu の背景を変える部分の書いてます)



Google Docs Viewer 使ってみました。

Android アプリのサイズ関係めも

1. apk ファイルサイズの上限
 ・50MB app package *

2. Android Market に archive できるサイズ
 ・ Support up to 4 GB *
 ・ Up to two 2GB archives *

3. asset フォルダ
 ・ 1ファイルの上限は 1M
 ・ 例えば、asset 内のDBファイルを初回起動時にデバイスの
   sqlite にコピーする場合など、ファイルが 1M を超えるなら
  分割する必要がある。

4. Internal Storage の容量 (/data/data/(app_name)/フォルダ以下)
 ・ 端末の内部メモリの空き容量 - α ?

 * Google I/O 2011 の Android Merket for Developers セッションで紹介されている Android Market での制限

Android NumberPicker を拡張して ItemPicker を作ってみた。

Android には日時を設定するための DatePicker, 時刻を設定するための TimePicker が用意されています。これらの Picker の元になっているのが NumberPicker です。ちなみに NumberPicker は非公開クラスになっています。

この NumberPicker のレイアウトでは、 + ボタンが上にあるために、+ ボタンを押している間、設定している値が指で見えなくなってしまいます。そこで、この NumberPicker を元にして + ボタンと - ボタンが設定値の左右にある Picker を作ってみました。

ItemPicker at yanzm/yanzm-s-Custom-View-Project - GitHub



ついでに、ボタンと入力部分の画像リソースと、選択範囲および選択アイテムを attribute として指定できるようにしました。

こんな感じで、XML から値の設定などが全部できます。 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/yanzm.products.customview.itempicker" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <DatePicker android:id="@+id/datePicker1" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TimePicker android:id="@+id/timePicker1" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <yanzm.products.customview.itempicker.ItemPicker android:layout_width="180dip" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:text="+" custom:start="0" custom:end="10" custom:current="2" /> <yanzm.products.customview.itempicker.ItemPicker android:layout_width="240dip" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:text="+" custom:start="1" custom:end="9" custom:current="2" custom:speed="100" custom:displayedValue="@array/color_names" /> <yanzm.products.customview.itempicker.ItemPicker android:layout_width="240dip" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:text="+" custom:start="1" custom:end="9" custom:current="4" custom:incrementBackground="@drawable/picker_bg" custom:decrementBackground="@drawable/picker_bg" custom:editTextBackground="@drawable/input_bg" custom:displayedValue="@array/color_names" /> </LinearLayout>

attribute として用意したのは
  • incrementSrc : 増加ボタン (ImageButton) の 画像リソース
  • decrementSrc : 減少ボタン (ImageButton) の画像リソース
  • incrementBackground : 増加ボタン (ImageButton) の 背景画像リソース
  • decrementBackground : 減少ボタン (ImageButton) の背景画像リソース
  • editTextBackground : 設定値 (EditText) の背景画像リソース
  • start : 最少値 (int)
  • end : 最大値 (int)
  • current : 現在の値 (int)
  • speed : ボタン長押し時の自動増加/減少の切り替え速度
  • displayedValue : 数字ではなく文字を設定値にする場合の文字列配列。最小値が index 0 にあたる


'},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

ページビューの合計