2014年02月12日

[Cocos2d-x] 階層化されたCCLayerの内側からモーダルレイヤを画面の中心に表示する(改)

以前、以下のような記事を書きました。
tappli blog: [Cocos2d-x] 階層化されたCCLayerの内側からモーダルレイヤを画面の中心に表示する
親階層との位置を計算してモーダルレイヤを中心に表示するというものでした。
今日ふと気づいたのですが、そんな面倒な計算をしなくても親階層に追加(addChild)すれば良いだけだったのでは…。
CCNode *parent = this;
while (parent->getParent()) {
parent = parent->getParent();
}
parent->addChild(modal);

こんな感じ。
問題なさそう。

posted by t2low at 22:00| Cocos2d-x

2014年02月05日

[Cocos2d-x] Classesの中を整理する

Cocos2d-xの開発をEclipseで行うときの設定です。
Xcodeだとこの辺はあまり気にしなくても良い感じになってますね。

Cocos2d-xでプロジェクトを作ると、Classesに4つのファイルができます。
Classes/
├AppDelegate.cpp
├AppDelegate.h
├HelloWorldScene.cpp
└HelloWorldScene.h

最初のうちは良いのですが、ファイルが増えてくるとわかりにくくなります。
↓こんな感じ。わかりにくいですね。
Classes/
├AppDelegate.cpp
├AppDelegate.h
├Fuga.cpp
├Fuga.h
├HelloWorldScene.cpp
├HelloWorldScene.h
├Hoge.cpp
├Hoge.h
├Piyo.cpp
└Piyo.h

こうなってしまう前にフォルダにまとめたいですね。
Classes/
├AppDelegate.cpp
├AppDelegate.h
├HelloWorldScene.cpp
├HelloWorldScene.h
└HogeHoge/
 ├Fuga.cpp
 ├Fuga.h
 ├Hoge.cpp
 ├Hoge.h
 ├Piyo.cpp
 └Piyo.h

しかし、ファイルの場所を変えてしまうとビルドできなくなってしまいます。
ファイルが参照できるようにしましょう。
// before
#include "Hoge.h"
// ↓
// after
#include "HogeHoge/Hoge.h"

としても参照できますが、一つ一つ変更するのはめんどくさいです。
Makefile(Android.mk)の中にHogeHogeからもincludeできるように指定するのが良い気がします。
↓このようにしておけば、#include "Hoge.h"のまま参照可能です。
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
$(LOCAL_PATH)/../../Classes/HogeHoge/

ソースファイルの場所も修正しておきましょう。
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp \
../../Classes/HogeHoge/Hoge.cpp \
../../Classes/HogeHoge/Fuga.cpp \
../../Classes/HogeHoge/Piyo.cpp

これでビルドできるようになるはずです。
ソースをグループ化できるのでわかりやすくなりますね。
posted by t2low at 22:00| Cocos2d-x

2014年02月03日

[Android] アプリの背景に設定されている壁紙(ライブ壁紙)を使う

アプリの背景に端末に設定された壁紙を利用したくて、以前こんな記事を書きました。

tappli blog: [Android] 壁紙を取得する

この方法で(静止画の)壁紙を取得することができるのですが、ライブ壁紙は取得できません。
ライブ壁紙が設定されていても、静止画の壁紙が返ってくるのです。
WallpaperManager#getWallpaperInfo()を使えば、ライブ壁紙の情報やサムネイル画像は取得できるのですが、背景として使うための画像は取得できそうにありませんでした。

いつものように検索してみると…

【ご助言お願いします】ホームアプリ作成での、ライブ壁紙を壁紙に配置する方法について - Google グループ

いつもいつも先達の知識に助けられてばかりです。ありがたいことです。
上のリンク先にも書かれていますが、テーマを設定するだけっぽいですね。
android:theme="@android:style/Theme.Wallpaper"

これだけでアプリの背景が壁紙と同じものになります。

posted by t2low at 22:00| Android

2014年01月30日

[Android] INSTALL_REFERRER のBroadcastについて

Google Playからアプリをインストールしたときに送信される(らしい)INSTALL_REFERRERというBroadcastアクションがあります。
(正確なアクション名は"com.android.vending.INSTALL_REFERRER")
開発中のアプリに組み込むライブラリの関係上、これを2つのBroadcastReceiverで受け取る必要が出てきました。

今までの自分の理解では、Broadcastは複数のレシーバに送信されるイメージでした。
UDPみたいなイメージです(自分のUDPのイメージも間違ってるかもしれません)。
それがこのINSTALL_REFERRERについては、通用しませんでした。
Google Play側で1アプリにINSTALL_REFERRERを受信する2つのBroadcastReceiverがあると送信しないようにしているんでしょうか…。
そのため、以下のような実装を行いました。
public class CustomReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
AReceiver a = new AReceiver();
a.onReceive(context, intent);

BReceiver b = new BReceiver();
b.onReceive(context, intent);
}
}

たぶんこれで動作するようになったはず…。
BroadcastReceiverって自分でインスタンス作っても良いんです?
これが正しい実装なんです?
イマイチすっきりしません。

すっきりしないので、サンプルアプリを作って確認してみました。
1つのアプリで、同じアクションを受け取る2つのBroadcastReceiverを定義して、adbからコマンド打って流してみたのです。
結果は2つともちゃんと受信しました…。
やっぱり受信しますよね。
Google Play側でそういう実装にしてるということなんですかねぇ…。
詳しい方がいましたら教えていただけると幸いですmm

posted by t2low at 23:00| Android

2014年01月29日

[Android] 強制停止するとBroadcastが受信できない

今開発中のアプリでBroadcastReceiverを使っています。
Manifestに書くだけで受信できるタイプのBroadcastを受け取るBroadcastReceiverです。

設定からアプリを「強制停止」させると、これが受信できなくなりました。
そういえば、いつのバージョンからかそういうことになっていた気がします。
検索したら↓こちらのブログが見つかりました。Android3.1以降だそうです。

Yukiの枝折: Android:Broadcastを受信できないアプリのSTOP状態

こちらの記事には、「一度も起動していない状態」のことは書かれていますが、「強制停止」したときのことは書かれていません。
たぶん同じだろうとは思いましたが、一応確認することにしました。
エミュレータでNexus4(API LEVEL 16)を作成して、"/data/system/packages-stopped.xml"を探します。
しかし、"/data/system/"に"packages-stopped.xml"がありません。
ソースコードを見てみると、記録されるファイルが変わっていました。
新しい場所は"/data/system/users/0/package-restrictions.xml"でした。(0はユーザーのID)
マルチユーザが導入されたのはAndroid4.2からだと思ってましたが、内部的にはAndroid4.1の頃からあったんですね。
XMLの中身も変わっているようです。こんな感じでした。
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<package-restrictions>
<pkg name="com.hoge.app" stopped="true" nl="true" />
<pkg name="com.fuga.app" stopped="true" />
<pkg name="com.piyo.app" />
</package-restrictions>

一度も起動していないと「nl="true"」付くようです。
停止状態だと「stopped="true"」が付くようです。これが付いているとBroadcastを受け取れないんですね。
お勉強になりました。

posted by t2low at 22:00| Android

2014年01月23日

[Android] Fragment内のWebViewで先読みするにはどうすれば良いだろう?(2)

以前、以下の様な記事を書きました。

tappli blog: [Android] Fragment内のWebViewで先読みするにはどうすれば良いだろう?

結局うまいこと出来なかったのでした。
今回、また先読みの要望があがりました。
前回のように「ダイアログ風のレイアウト」で済ますのは難しそうな状況です。

Viewを渡すメソッドを作れば渡せないこともないと思いますが、それはちょっとねぇ。


前回、こんなことを書きましたが、これはFragmentのインスタンスが再生成されたときに、ちゃんと表示されないことが容易に想像できたからです。
今回、ふと思いつきました。逆ならいけるんじゃないかと。
FragmentのonCreateView()、またはDialogFragmentのonCreateDialog()あたりで、呼び出し元のActivityが特定のinterfaceを実装しているかチェックし、実装していたらそのinterfaceのメソッドでWebViewを取得する。
WebViewに表示するページはActivityで予め読み込んでおく、という寸法です。
これならインスタンスがシステムによって破棄されても、呼び出し元のActivityの再生成されるはずなので、WebViewが表示できないということはないはず…。
このやり方がイケていないというのはわかっていますが、試してみたところ、Fragment表示直後にWebページを表示したWebViewを表示することができました。

イケてないけど、動くことが大事!
と自分に言い聞かせているところです。
posted by t2low at 23:00| Android

2014年01月21日

[Android] 画像と文字列を下端で揃えたいとき

画像と文字列の下端を揃えたいという要望がありました。
RelativeLayoutでlayout_alignBottomを設定すると以下のようになります。
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp" >
<ImageView
android:id="@+id/green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:src="@drawable/green" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/green"
android:background="#ddf"
android:layout_toRightOf="@id/green"
android:text="テスト"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>

align_bottom.png
しかし、これでは上の画像のように、文字列の下に少し隙間が開いてしまいます。
フォントにはdescentという部分があるためですね。

descentを考慮して画像と文字列の下端を合わせたいときはlayout_alignBaselineを使います。
同時に画像を表示するImageViewにはbaselineAlignBottomをtrueにしておく必要があります。
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp" >
<ImageView
android:id="@+id/green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:baselineAlignBottom="true"
android:src="@drawable/green" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/green"
android:layout_toRightOf="@id/green"
android:background="#ddf"
android:text="テスト"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>

align_baseline.png
こんな感じです。
これで画像と文字列の下端が揃いました。

posted by t2low at 22:00| Android

2014年01月20日

[Android] デフォルトで起動するアプリの判定

デフォルトで起動するように設定されているホームアプリの取得方法を調べてみました。
PackageManagerから簡単に習得できるんじゃないかと考えて、適当にクラスを眺めていましたが、見つからないので結局コードを追いかけることに…。

どうやらgetPreferredActivities()というメソッドを使えば良いようです。
String defaultHomeApp = "";

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);

PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
for (ResolveInfo info : list) {
List<IntentFilter> filters = new ArrayList<IntentFilter>();
List<ComponentName> activities = new ArrayList<ComponentName>();
pm.getPreferredActivities(filters, activities, info.activityInfo.packageName);
if (activities.size() > 0) {
defaultHomeApp = activities.get(0).toString();
break;
}
}
Log.d("LOG", "Home app : " + defaultHomeApp);



posted by t2low at 23:00| Android

2014年01月19日

[Mac] テレビとHDMI接続した

職場はデュアルモニタです。が、自宅はそうではありません。
画面が狭いのは不便なので、↓の商品を買いました。



送料無料で400円。
なんでこんなに安くできるんでしょうか。
16日に注文して、18日に届きました。
早いですね。
安かったので若干不安はありましたが、繋いでみたら問題なく表示されました。

大画面で表示できるのは良いのですが、自宅にあったHDMIケーブルの長さが足らないのに気づいていませんでした…。
今のままではちょっと使うのが厳しいです。どうしたものか。
posted by t2low at 00:10| Mac/iOS

2014年01月17日

[C++] double型を3桁ずつカンマで区切られた文字列に変換する

double型を3桁ずつカンマで区切られた文字列に変換する。
たったこれだけのことにえらい苦労しました。
C++の基本的なとこがわかっていないのですね。C++の基礎をひと通り勉強したほうが良さそうです。

良し悪しはともかく出来上がったのは以下のようなコード。
std:string str;
double value = 99999999.999;

std::stringstream stream;
stream << std::setprecision(2) << std::setiosflags(std::ios::fixed) << value;
stream >> str;

int signLen = value < 0 ? 1 : 0;
int dotPos = str.find('.');
for (int pos = dotPos - 3; pos > signLen; pos -= 3) {
str.insert(pos, ",", 1);
}

insert()で1個ずつカンマを挿入するようにしましたが効率は悪そう…。

参考:
cp_C++言語(予備知識) 

posted by t2low at 23:00| Cocos2d-x