2015/12/29

GTK+ で Label の背景色を変更する

Windowless Widget は背景色を変更することができない

Label, Button, Paned, Frame などの Windowless Widget は背景色を変更することが出来ないそうです。
そのため、以下のようなコードを書いても背景はデフォルトのままです。

// 以下は Gtkmm のコードですが、GTK+ でも同様に書くと動作しません
Gtk::Label* label = Gtk::manage(new Gtk::Label());
label->modify_bg(Gtk::STATE_NORMAL, bg_color);
label->set_label(message);
widget->add(*label);

背景色は EventBox で変える

ではどうするのかと言うと、以下のように EventBoxLabel 等を入れ子にして、 EventBox の背景色を変えるという方法を使うようです。

Gtk::Label* label = Gtk::manage(new Gtk::Label());
label->set_label(message);
Gtk::EventBox* ebox = Gtk::manage(new Gtk::EventBox());
ebox->modify_bg(Gtk::STATE_NORMAL, bg_color);
ebox->add(*label);
widget->add(*ebox);

参考
以下に情報がありますPython インターフェースですが
PyGTK FAQ Entry

2015/12/25

zsh でインストールされていないコマンドを叩いた場合、パッケージ名を推測して教えてくれるようにする

@Ubuntu 14.04 LTS

zsh では bash のような機能が働かない

Ubuntu の bash では、インストールされていないコマンドを叩いた場合、以下のように類推したパッケージ名を教えてくれて便利です。
$ vld
No command 'vld' found, did you mean:
 Command 'gld' from package 'postfix-gld' (universe)
 Command 'vlc' from package 'vlc-nox' (universe)
 Command 'bld' from package 'bld' (universe)
 Command 'fld' from package 'kon2' (universe)
 Command 'vl' from package 'atfs' (universe)
 Command 'ld' from package 'binutils' (main)
vld: command not found

ところが、zsh だとエラーメッセージだけ。
% vld
zsh: command not found: vld

zsh でも出来るようにする

これを bash 風に変えるには以下を設定ファイルに追加します。

~/.zshrc (or /etc/zshrc)
if [[ -f /etc/zsh_command_not_found ]] then
  source /etc/zsh_command_not_found
fi

command-not-found がインストールされていない場合

/etc/zsh_command_not_found が存在しない場合は、インストールしましょう。

% sudo apt-get install command-not-found

2015/10/10

AndroidStudio で Generate Signed APK を実行したら "Unable to compute hash of ..." と出た場合の対処方法

AndroidStudio で署名した APK を作成しようとしたら以下のようなエラーがでてしまいました AndroidStudio 1.4
compileSdkVersion 23
buildToolsVersion "23.0.1"

2015/09/20

AVD を立ち上げようとしたら libstdc++.so.6 が無いと言われた on Ubuntu 14.04

諸事情で Ubuntu 14.04 LTS (64bit) をクリーンインストールしました。

その後、Android Studio を立ち上げ、普通に使っていたのですが、AVD を起動しようとすると、以下のようなエラーが。

Cannot launch AVD in emulator.
error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory


確認してみるも、libstdc++6はちゃんとインストールされている様子。
これ、以前もハマったやつだ!
というわけで、32bit 系のライブラリを用意してやることで解決しました。
$ sudo apt-get install lib32stdc++6

ちょっと古い記事だと「ia32-libs をインストールせよ。」と書いてあるものもあるのですが、Ubuntu 13.10 からはライブラリが分割されたみたいです。

2015/09/13

VirtualBox で Raw disk vmdk を作ろうとした時に VERR_ACCESS_DENIED が出る時の対処方法 on Ubuntu 14.04

VirtualBox で Raw disk にアクセスできるようにするには、vmdk ファイルを作るのが一般的のようです。
しかし、普通に作成しようとすると、以下のように VERR_ACCESS_DENIED が出てしまいます。
VBoxManage internalcommands createrawvmdk -filename ~/text.vmdk -rawdisk /dev/sda
VBoxManage: error: Cannot open the raw disk '/dev/sda': VERR_ACCESS_DENIED
VBoxManage: error: The raw disk vmdk file was not created

アクセス権の問題なので、sudo を使えば回避できるのですが、その場合、virtualbox 自体もスーパーユーザー権限で起動しないといけません。 そうしないと、以下のようなエラーが発生してしまいます。
Failed to open the hard disk file /home/yusuke/text.vmdk.

Permission problem accessing the file for the medium '/home/yusuke/text.vmdk' (VERR_ACCESS_DENIED).

Result Code: VBOX_E_FILE_ERROR (0x80BB0004)
Component: Medium
Interface: IMedium {05f2bbb6-a3a6-4fb9-9b49-6d0dda7142ac}
Callee: IVirtualBox {fafa4e17-1ee2-4905-a10e-fe7c18bf5554}
Callee RC: VBOX_E_OBJECT_NOT_FOUND (0x80BB0001)

しかし、せっかくの仮想環境をスーパーユーザー権限で起動するのはセキュリティ的にも問題があります。

自分を disk グループに追加するだけで良い

実は、これには簡単な回避方法があります。
以下のように自分を disk グループに追加してやるのです。(追加したあとは、再起動が必要です)

$ sudo gpasswd -a YOUR_USERNAME disk

すると、vmdk の作成も、virtualbox の起動も、先のユーザで問題なく実行できるようになります。

グループを調べる

Ubuntu 14.04 であれば、disk グループで間違いないと思いますが、こういうのは時々変わったりするので書いておきます。
以下のように、 デバイスファイルのグループ名とグループアクセス権を確認可能です。
% ls -al /dev/sd*
brw-rw---- 1 root disk 8,  0  9月 13 14:17 /dev/sda
brw-rw---- 1 root disk 8,  1  9月 13 11:36 /dev/sda1
brw-rw---- 1 root disk 8,  2  9月 13 11:36 /dev/sda2
brw-rw---- 1 root disk 8,  3  9月 13 11:36 /dev/sda3
brw-rw---- 1 root disk 8, 16  9月 13 11:36 /dev/sdb
brw-rw---- 1 root disk 8, 17  9月 13 11:36 /dev/sdb1
brw-rw---- 1 root disk 8, 32  9月 13 11:36 /dev/sdc
brw-rw---- 1 root disk 8, 33  9月 13 11:36 /dev/sdc1
brw-rw---- 1 root disk 8, 48  9月 13 11:36 /dev/sdd

2015/08/31

Android Studio を起動しようとしたら IllegalArgumentException が発生した on Ubuntu

Android Studio を新規にインストールしなおしたら以下のようなエラーが出て、起動しなくなってしまいました。

Internal error. Please report to https://code.google.com/p/android/issues

java.lang.RuntimeException: java.lang.IllegalArgumentException: Argument for @NotNull parameter 'name' of com/android/tools/idea/welcome/Platform.<init> must not be null
    at com.intellij.idea.IdeaApplication.run(IdeaApplication.java:178)
    at com.intellij.idea.MainImpl$1$1$1.run(MainImpl.java:52)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:362)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.lang.IllegalArgumentException: Argument for @NotNull parameter 'name' of com/android/tools/idea/welcome/Platform.<init> must not be null
    at com.android.tools.idea.welcome.Platform.<init>(Platform.java)
    at com.android.tools.idea.welcome.Platform.getLatestPlatform(Platform.java:72)
    at com.android.tools.idea.welcome.Platform.createSubtree(Platform.java:89)
    at com.android.tools.idea.welcome.InstallComponentsPath.createComponentTree(InstallComponentsPath.java:81)
    at com.android.tools.idea.welcome.InstallComponentsPath.init(InstallComponentsPath.java:215)
    at com.android.tools.idea.wizard.DynamicWizardPath.attachToWizard(DynamicWizardPath.java:97)
    at com.android.tools.idea.wizard.DynamicWizard.addPath(DynamicWizard.java:233)
    at com.android.tools.idea.welcome.FirstRunWizard.init(FirstRunWizard.java:75)
    at com.android.tools.idea.welcome.FirstRunWizardHost.setupWizard(FirstRunWizardHost.java:100)
    at com.android.tools.idea.welcome.FirstRunWizardHost.getWelcomePanel(FirstRunWizardHost.java:92)
    at com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame.<init>(WelcomeFrame.java:68)
    at com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame.showNow(WelcomeFrame.java:173)
    at com.intellij.idea.IdeaApplication$IdeStarter.main(IdeaApplication.java:302)
    at com.intellij.idea.IdeaApplication.run(IdeaApplication.java:172)
    ... 16 more

修正方法

「困ったな」と思って探してみると、既知の問題だったようで、すでに答えが出ていました。

というわけで、idea.properties に以下の一行を加えればOKです。

android-studio/bin/idea.properties
disable.android.first.run=true

2015/08/14

VAIO Z を Windoes 10 にアップグレードしたらファンが激しく回るようになってしまった

我が家の VAIO Z (VPCZ21AJ) を Windows 10 にアップグレードしたのですが、直後からファンの音がすごい。
明らかに本気で回っている感じ。
今までも、CPU を酷使している時等にはこれくらい回っていたことがあったけど、今回は CPU の使用率も低めなのに止まらない。

これは Windows 7 に戻さないといけないかもしれないと諦めかけて、とりあえず電源の設定をいじってみると、なんとファンが大人しくなりました。

コントロールパネル → ハードウェアとサウンド → 電源オプション → 省電力を選択


試しに、「バランス」に戻してみたところ、またファンが回りだしたので、この設定が効いているのは間違いない様子です。

2015/08/12

Windows 7 から Windows 10 にしたら画面の解像度がおかしくなったので修正

結構早めに予約しておいたのに、やっと昨日になって Windows 10 の更新が行われました。
で、早速使ってみたところ、画面の解像度がおかしい。
特に、昔から使っているデスクトップアプリの表示域が明らかに一昨日までのものより狭くなってる。 そして、その分、文字とかが大きくなっている。
使いづらすぎる…

というわけで、いろいろ確認してみたところ、原因がわかったので書きとめておきます。

画面の解像度を確認

Windows ボタン → 設定 → システム、ディスプレイ、通知、アプリ、電源

ディスプレイの詳細設定

解像度を確認するも、問題なく最大解像度になっています。

拡大率を確認

先ほどの設定画面の中で気になる項目がありました。
それが、「テキスト、アプリ、その他の項目のサイズを変更する: 150%(推奨)」です。

150% ってどういうこと?

拡大率を修正

この 150% が怪しいと思い、この項目を 100% にしてみると…
ビンゴ!

表示が昔のように戻りました。
アプリによっては一度ログアウトしないと反映されないようです。

ちょっと小さすぎる

そのまま使っていたのですが、アプリによっては、表示が小さくなりすぎてしまうようです。
仕方がないので、今は 125% にして使っています。

拡大率を任意の数値にすることも可能

先に紹介した方法だと、100%, 125%, 150% とキリの良い数字しか選択できなかったのですが、これを任意の数字にする方法も存在します。

コントロールパネル → デスクトップのカスタマイズ → ディスプレイ → カスタムの拡大率を設定

ただ、推奨されないとのことなので、私はキリの良い 125% で我慢することにしました。

2015/07/24

Android Studio で "Invalid Gradle JDK configuration found." が出た時の対処法

久しぶりにサブのノートPCで Androidアプリ開発をしようとしたら、以下のようなエラーが出てしまいました。
Invalid Gradle JDK configuration found. Open Gradle Settings
Platform SDK does not point to valid JDK (C:\Program Files\Java\jdk1.8.0_20)

原因

「そういえば、Java をアップデートしたような気もする」と思って 確認してみると、Java がインストールされているディレクトリは C:\Program Files\Java\jdk1.8.0_45 になっていましたバージョンは同じ1.8.0だけど、アップデートが違う

修正方法

JDK のディレクトリ指定を更新すれば良いはずなので、Project Structure を開きます。

File → Project Structure...


SDK Location の中に JDK Location という項目があるので、そこを修正します。

デフォルト設定も変更しておく

先の方法だと、開いているプロジェクトの設定だけ修正されるので、デフォルト設定も変えておくと良いでしょう。

File → Other Settings → Default Project Structure...

知っていれば何てことは無い問題ですが、実際起こると「あれ、設定ってどこで出来るんだっけ?」ってなりますね。
特に今回、エラーメッセージの Open Gradle Settings をクリックすると全然違う設定画面が出てしまったAndroid Studio 1.2.2 での動作ので、ちょっと戸惑いました。

2015/07/11

Hulu の文字化けを直す on Ubuntu 14.04

2年ほど前に同様の記事を書いたのですが、その後、Hulu を見るのは携帯端末や Chromecast がメインになり、Ubuntu で Hulu を見ることは無くなってしまいました。

ところが、先日、久しぶりに Ubuntu 上の Chrome で見てみたら、見事に文字化け…画像は使い回しです
フォントの設定とかは変わっていないのにUbuntu のバージョンは上がってますが、普通にアップデートしただけ

2015/07/10

Atom の文字化けを直す on Ubuntu 14.04

Atom、いいですね。
1.0.0 になってから使い始めたので、まだ使い込めてはいないのですが、とりあえず自分の持つ全ての環境にインストールしてみました。

しかし、Ubuntu 14.04 で日本語が文字化け。
文字コードは合っているはずなのに!

どうやら日本語フォントの指定が間違っているそもそも、指定されていない?様子。
ネットでフォント指定の方法を調べてみるも、File → Settings を開けと書いてある。
しかし、そのようなメニューはないAtom のバージョンは 1.0.2

Windows 版だと確かにあるのだけど…。
「これはバグか?」と思ったら、ありましたよ。File ではなく、Edit に!

Settings ではなく Preferences になってるしまぎらわしー!
まぁ、まだ 1.0.0 が出たばかり。これからそういうところが整理されていくのでしょう


というわけで、Settings (Preferences) からフォントを指定すればオッケーです。
ただ、個人的には Settings を使うより、Stylesheet を使ったほうが良いのではないかと思うのですが。

2015/07/09

Atom でフォントを変更する方法は2通りある

正確には、「Atomエディタ部分のフォントを変更する方法は 2通りある」です検証した Atom のバージョンは 1.0.2
一つは Settings を使う方法。
もう一つは Stylesheet を変更する方法。

後者はエディタだけでなく、その他のコンポーネントの見た目も変更できます。

2015/06/25

productFlavors で src ディレクトリ以下を切り替える

ProductFlavors を使って Free version と Pro version を作り分ける際、ソースコードやリソースを切り替えることが出来ます。

ProductFlavors を使って Free version と Pro version を作り分ける (Android Studio)

AndroidStudio には apk を出し分ける機能がついています。
ProductFlavors という機能で、 典型的な使い方は、Free version と Pro version を出すという場合でしょう最近はアプリ内課金で広告の有り無しを切り替えることが多いと思うので、需要は高くないかもしれません。

2015/06/14

CMake でドロップダウンリストから値を選択できるようにする

CMake を使っていると、「どのパラメータを設定すれば良いんだっけ?」とか「このパラメータに入れられる値って何だっけ?」な状態になることがありますこの手のビルドツールではよくあることですが。
せっかく GUI があるのだから、ドロップダウンリストで表示できたら良いのに。と思っていたら、既にそんな機能がありました。

2015/06/13

OpenLayers 3 で Feature 毎にアイコン画像や文字を変更する

OpenLayers 3 のマーカーに文字を表示する方法 2種 では固定の Style を適用する方法を紹介しましたが、場合によってはこれでは不便なので、Feature 毎に Style を変更する方法も用意されています。

2015/06/12

OpenLayers 3 のマーカーに文字を表示する方法 2種

OpenLayers 3 でマーカーを表示する方法 2種 でマーカーを表示できるようになったので、今度は文字を表示してみたいと思います。

2015/06/10

OpenLayers 3 でマーカーを表示する方法 2種

調べた限り、OpenLayers 3 でマーカーを表示する方法は2通りある様子OpenLayers 3.6.0 で確認

2015/05/02

Android Studio で Warning や Error の一覧を表示する

Android SDK を更新したら Warning が増えてしまいました。
問題になりそうなところを教えてくれるのは良いのですが、修正するには一覧で確認したいもの。
というわけで、一覧表示する方法を調べました。

Analyze → Inspect Code...

対象の範囲を選びます。

Analyze が終了すると、左下に Inspection というウィンドウが作成され、一覧が表示されます。

左のボタンで表示を切り替え可能なので、使いやすいようにカスタマイズします。
お勧めは、赤と黄色のボタン、"Group Inspections By Severity" です。
以下のように Error, Warning, Typo で分類してくれます。

2015/04/12

AndroidStudioで Java Library を追加したら UNEXPECTED TOP-LEVEL EXCEPTION でコンパイルが通らなかった場合の対処方法

現象

UNEXPECTED TOP-LEVEL EXCEPTION もいろいろなケースがあるので、一概に言えないのですが、以下のように ParseException: bad class file magic or version の場合、コンパイルに使った Java のバージョンが合っていない可能性が高いです。

...省略
:app:preDexDebug
AGPBI: {"kind":"SIMPLE","text":"UNEXPECTED TOP-LEVEL EXCEPTION:","position":{},"original":"UNEXPECTED TOP-LEVEL EXCEPTION:"}
AGPBI: {"kind":"SIMPLE","text":"com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)","position":{},"original":"com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)","position":{},"original":"\tat com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)","position":{},"original":"\tat com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)","position":{},"original":"\tat com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)","position":{},"original":"\tat com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:704)","position":{},"original":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:704)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)","position":{},"original":"\tat com.android.dx.command.dexer.Main.processFileBytes(Main.java:673)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.access$300(Main.java:83)","position":{},"original":"\tat com.android.dx.command.dexer.Main.access$300(Main.java:83)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)","position":{},"original":"\tat com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:602)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)","position":{},"original":"\tat com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)","position":{},"original":"\tat com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)","position":{},"original":"\tat com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.processOne(Main.java:632)","position":{},"original":"\tat com.android.dx.command.dexer.Main.processOne(Main.java:632)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)","position":{},"original":"\tat com.android.dx.command.dexer.Main.processAllFiles(Main.java:510)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.runMonoDex(Main.java:280)","position":{},"original":"\tat com.android.dx.command.dexer.Main.runMonoDex(Main.java:280)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.run(Main.java:246)","position":{},"original":"\tat com.android.dx.command.dexer.Main.run(Main.java:246)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.dexer.Main.main(Main.java:215)","position":{},"original":"\tat com.android.dx.command.dexer.Main.main(Main.java:215)"}
AGPBI: {"kind":"SIMPLE","text":"\tat com.android.dx.command.Main.main(Main.java:106)","position":{},"original":"\tat com.android.dx.command.Main.main(Main.java:106)"}
AGPBI: {"kind":"SIMPLE","text":"...while parsing com/kokufu/lib/Test.class","position":{},"original":"...while parsing com/kokufu/lib/Test.class"}
AGPBI: {"kind":"SIMPLE","text":"1 error; aborting","position":{},"original":"1 error; aborting"}

私の環境で Java のバージョンを調べてみると、以下のように 1.8 でした。

$ java -version
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

解決方法

2015/4/12 現在、Android Studio は Java 1.7 系でコンパイルするようですので、以下のように Java Library のコンパイルバージョンを下げます。

lib/build.gradle
apply plugin: 'java'

sourceCompatibility = '1.7'

Android Application のコンパイルバージョンを変更する

おまけですが、Android Application の方のコンパイルバージョンも変更することが出来ます。
以下のように Source Compatibility を選択すればオーケー。
現時点では 1.8 が選択肢にないです。

File → Project Structure

2015/03/19

DialogFragment の中に Fragment を表示する方法

ちょっと複雑な Dialog を表示しようと思った場合、DialogFragment の中に Fragment を表示したいということがあるかと思います。
しかし、XML を使った静的な Fragment は入れ子構造に出来ないようです。

では、どうしたら良いのかというと、動的に Fragment を追加してやれば良いです。
以下のように、onViewCreated() で Fragment を追加します。この時、getChildFragmentManager() を使用していることに注意です。

TestDialog.java
public class TestDialog extends DialogFragment {
    public TestDialog() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dialog_test, container, false);
        return v;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Fragment innerFragment = new InnerFragment();
        getChildFragmentManager().beginTransaction().add(R.id.fragment, innerFragment).commit();
    }
}

dialog_test.xml
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

2015/02/09

Gradle で Configuration with name 'default' not found. が出てしまった時の対処方法

Gradle で app と lib のように 2つの依存関係のあるモジュールを開発していると、以下のようなエラーが出てしまうことがあります。

A problem occurred configuring project ':app'.
> Cannot evaluate module lib : Configuration with name 'default' not found.

解決策1: app から対象の Configuration を明示的に指定する

Configuration は plugin を適用すると大抵は自動的に設定されます。 java とか com.android.application だと default という名前の Configuration があるので問題ないのですが、その他のものの場合は default がない場合があります。その場合は、対処の Configuration を以下のように明示的に指定することで回避することができます。
project の引数に path: が追加されているのに注意してください。

app/build.gradle
dependencies {
    compile project(path: ':lib', configuration: 'compile')
}

解決策2: lib に default という名前の Configuration を作る

lib にプラグインを適用してない等、Configuration がそもそもない場合は、以下のように自分で作成してしまうのも手です。

lib/build.gradle
configurations.create('default')

2015/01/27

ActionBarActivity#setSupportActionBar() で NoClassDefFoundError が発生する端末がある

私が Google Play で公開しているアプリのクラッシュ報告に、以下のような Stack Trace が送られてきました。
java.lang.NoClassDefFoundError: android.support.v7.internal.view.menu.MenuBuilder
at android.support.v7.widget.ActionMenuView.getMenu(ProGuard:620)
at android.support.v7.widget.Toolbar.ensureMenu(ProGuard:825)
at android.support.v7.widget.Toolbar.getMenu(ProGuard:817)
at android.support.v7.internal.app.ToolbarActionBar.getMenu(ProGuard:554)
at android.support.v7.internal.app.ToolbarActionBar.setListMenuPresenter(ProGuard:558)
at android.support.v7.app.ActionBarActivityDelegateBase.setSupportActionBar(ProGuard:178)
at android.support.v7.app.ActionBarActivity.setSupportActionBar(ProGuard:92)
at com.kokufu.android.apps.divelogbook.MainActivity.onCreate(ProGuard:84)
at android.app.Activity.performCreate(Activity.java:5122)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1150)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2315)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2403)
at android.app.ActivityThread.access$600(ActivityThread.java:165)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5391)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)

原因

調べてみると、Samsung やその他一部の端末で発生するバグらしい。

対策

これ、appcompat-v7 のバグではなく、OS のバグだと思われます。 OS に古い appcompat-v7 が組み込まれているのが問題ではないかと。
つまり、アプリ側ではどうしようもない。 …と諦めかけてたのですが、ProGuard を使って回避するナイスなアイデアが!

難読化をしない場合、以下の一行を ProGuard の設定ファイルに記述すればオッケーです。
-keep class !android.support.v7.internal.view.menu.**,** {*;}

他にも難読化したい場合には、以下の方が無難でしょう。
-keep class !android.support.v7.internal.view.menu.**,android.support.v7.** { *; }
-keep interface !android.support.v7.internal.view.menu.**,android.support.v7.** { *; }

出力された mapping ファイルを確認し、MenuBuilder の名前が変わっていることを確認しておきます。

build/outputs/mapping/release/mapping.txt
android.support.v7.internal.view.menu.MenuBuilder -> android.support.v7.internal.view.menu.i:

私の手元には、この問題が起こる端末が無いため、動作確認出来ていません。
名前変えただけで、class path の問題を回避できるんだか、ちょっと不安です。
もし、確認された方がいらっしゃいましたら、是非教えてください。

2015/01/20

Android 5.0 で LVL を使うと IllegalArgumentException が発生する

Android Developer としては大分遅いほうだと思いますが、最近やっと手持ちの Nexus 7 を Android 5.0 にしました。
そこで、LVL を適用したアプリを立ち上げてみたところ、以下のようなエラーが。

Caused by: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.android.vending.licensing.ILicensingService }
       at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1674)
       at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1773)
       at android.app.ContextImpl.bindService(ContextImpl.java:1751)
       at android.content.ContextWrapper.bindService(ContextWrapper.java:538)
       at com.google.android.a.a.i.a(ProGuard:150)
       at com.kokufu.android.apps.sqliteviewer.MainActivity.l(ProGuard:69)
       at com.kokufu.android.apps.sqliteviewer.MainActivity.onCreate(ProGuard:65)
       at android.app.Activity.performCreate(Activity.java:5933)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
       at android.app.ActivityThread.access$800(ActivityThread.java:144)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5221)
       at java.lang.reflect.Method.invoke(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

調べてみると、バグらしい

結構、重大なバグだと思うのですが、これまで放って置かれているのは、LVL がソース提供だからでしょうか少なくとも 2015/1/20 現在の Google Play Licensing Library Rev. 2 では修正されていません。
リンクにもあるとおり、以下のように LVL の中身を修正することで問題は解決します。

LicenseChecker.java (修正前)
                    boolean bindResult = mContext
                            .bindService(
                                    new Intent(
                                            new String(
                                                    Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))),
                                    this, // ServiceConnection.
                                    Context.BIND_AUTO_CREATE);

                    if (bindResult) {
                        mPendingChecks.offer(validator);
                    } else {
                        Log.e(TAG, "Could not bind to service.");
                        handleServiceConnectionError(validator);
                    }

LicenseChecker.java (修正後)
                    Intent serviceIntent = new Intent(
                            new String(Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")));
                    serviceIntent.setPackage("com.android.vending");

                    boolean bindResult = mContext
                            .bindService(
                                    serviceIntent,
                                    this, // ServiceConnection.
                                    Context.BIND_AUTO_CREATE);