ActionBarSherlockでActionBarとViewPagerを連携する
ActionBarSherlockのFragmentデモにあるTabs and Pagerは、OSネイティブのタブUIを使っているため2.3以前の端末で動かしたときと4.0以降で動かしたときで表示が異なります。
そこで、ActionBarのタブとViewPagerを連携することでどの端末でも見た目を統一できます。
ソースコード全体は以下に置きました。
ダミーFragmentの作成
各タブに表示するためのダミーFragmentを作ります。
public class DummyFragment extends SherlockFragment { private int mNum; public static DummyFragment getInstance(int num) { DummyFragment fragment = new DummyFragment(); Bundle args = new Bundle(); args.putInt("num", num); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = this.getArguments(); mNum = (args != null) ? args.getInt("num") : 0; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView view = (TextView) inflater.inflate(R.layout.hello_world, container, false); view.setText("Tab" + mNum); return view; } }
ダミーFragmentのXMLファイル(hello_world.xml)
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/hello_text" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:text="@string/hello_world" android:textAppearance="?android:attr/textAppearanceMedium" />
FragmentPagerAdapterの作成
ViewPagerを管理するためにFragmentPagerAdapterのサブクラス(TabAdapterクラス)を作ります。
ActionBarでタブを使えるようにするためにActionBar.NAVIGATION_MODE_TABSを設定します。
mViewPager.setOnPageChangeListener()で設定するイベントについては後述します。
public TabAdapter(SherlockFragmentActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); mActionBar = activity.getSupportActionBar(); mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); mViewPager = pager; mViewPager.setOnPageChangeListener(mOnPageChangeListener); } @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); if (info != null) { if (info.fragment == null) { info.fragment = DummyFragment.getInstance(position); } return info.fragment; } else { return new Fragment(); } } @Override public int getCount() { return this.mTabs.size(); }
タブの追加処理
タブを追加できるよう、TabAdapterクラスにメソッドを追加します。
setTabListener()で設定するイベントについては後述します。
private final SparseArray<TabInfo> mTabs = new SparseArray<TabInfo>(); public void addTab(String tag, Class<?> clazz, Bundle args) { ActionBar.Tab tab = this.mActionBar.newTab(); tab.setText(tag); tab.setTabListener(mTabListener); this.mActionBar.addTab(tab); TabInfo info = new TabInfo(tag, clazz, args); mTabs.put(tab.getPosition(), info); }
タブ情報の管理クラス(TabInfoクラス)以下のように定義しました。
static final class TabInfo { public final String tag; public final Class<?> clss; public final Bundle args; public Fragment fragment; TabInfo(String _tag, Class<?> _class, Bundle _args) { tag = _tag; clss = _class; args = _args; } }
タブ制御イベントの追加
ActionBarのタブをタップしたときの制御イベントを定義します。
ActionBarとViewPagerは別制御なので、タブを選択したときにViewPagerを選択するようonTabSelected()メソッドに処理を追加します。
private final ActionBar.TabListener mTabListener = new ActionBar.TabListener() { @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } };
次にViewPagerからActionBarを制御するための制御イベントを定義します。
ViewPagerのページが切り替わったらActionBarのタブも切り替わるようにonPageSelected()メソッドに処理を追加します。
private final ViewPager.OnPageChangeListener mOnPageChangeListener = new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { mActionBar.selectTab(mActionBar.getTabAt(position)); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageScrollStateChanged(int state) { } };
Activityからの呼び出し
SherlockFragmentActivityのonCreateでタブの管理処理を呼び出します。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager pager = (ViewPager) findViewById(R.id.pager); TabAdapter tabAdapter = new TabAdapter(this, pager); pager.setAdapter(tabAdapter); tabAdapter.addTab("Tab1", DummyFragment.class, null); tabAdapter.addTab("Tab2", DummyFragment.class, null); tabAdapter.addTab("Tab3", DummyFragment.class, null); }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <FrameLayout android:id="@android:id/tabcontent" android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="0" /> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout>
これでAndroid 4.0より前の端末でも4.0のようなTab+ViewPagerが使えるようになります。
netduino pLusでfeLicaリーダー動かしてみました(補足編)
この投稿はLL/ML Advent Calendarの12/11向けの記事です。
いつものごとくTLを眺めていたら@teruroさんに
なんか人を増やしたらいいらしいから、@miguse と @nagakenjs も呼ぼうず #LLAdventJP
— てるるー 名古屋店さん (@terurou) 11月 20, 2012
と
LL/MLにちなむと言うことでいろいろ考えたのですが、先日のNGK2012Bで話した内容の補足をしようかと思います。発表資料はこちら。
補足と言っても全てを取り扱うことはできませんので、NetduinoとFeliCaリーダーの通信方法について触れたいと思います。
ハードウェア
今回紹介するのは次の二つです。通販サイトのスイッチサイエンスさんにリンクを張っています。
準備
開発環境の構築は先日書いた記事を参照して下さい。
NetduinoとRC-S620Sとはシリアル通信で接続します。
作りたてのソリューションではシリアルポートは使えませんので、参照の追加より「Microsoft.SPOT.Hardware.SerialPort」を追加します。
NetduinoとRC-S620Sの接続
Netduino Plusには、二つのシリアルポートがあります。
COM1がD0(RX)とD1(TX)、COM2がD2(RX)とD3(TX)となりますが、今回はCOM1の方を使います。
RC-S620Sのピンアサインはこうなっています。
ピン番号 | ピン名称 | 機能 | 備考 |
---|---|---|---|
1 | VDD | 電源端子 | DC3.3V±5%もしくはDC5.0V±5% |
2 | RXD | RXD信号 | |
3 | TXD | TXD信号 | |
4 | GND | GND端子 | GND接地 |
5 | Reserve | テスト出力端子 | コントローラ側でOpen処理が必要 |
6 | GND | GND端子 | GND接地 |
Netduinoと繋ぐにはクロス接続する必要があるので、互いの端子のRXとTXを繋ぐように配線します。ピン1は電源、ピン4と5はGNDなのでNetduinoの該当端子にそれぞれ繋ぎます。
Netduino PlusとRC-S620Sを繋いだ図が以下になります。
シリアル通信
シリアルポートを扱うには、System.IO.Ports.SerialPortクラスを使います。コンストラクタでポート名、ボーレート、パリティ、などのシリアル通信に必要な値を指定します。
処理を開始する前にOpenメソッドを実行し、ポートを開く必要があります。
SerialPort serialPort = new SerialPort(Serial.COM1, 9600, Parity.None, 8, StopBits.One); serialPort.Open(); // なにか処理 serialPort.Close();
シリアルポートにデータを書き込むのは簡単です。
SerialPortクラスのWriteメソッドにbyte配列を指定します。
byte[] buffer = new byte[] { 0x01, 0x02, 0x03 }; serialPort.Write(buffer, 0, buffer.Length);
シリアルデータの読み込みにはReadメソッドを使います。イベントハンドラを用いる非同期なやり方もあるのですが、RC-S620Sでは頻繁に応答があるためReadメソッドを使った同期的なやり方を採用しました。
始めに受信したいバイト数(例では256バイト)分シリアルポートにデータがたまるまで待機し、Readメソッドでたまったデータをバッファに読み込みます。
byte[] buffer = new byte[256]; int len = buffer.Length; while (serialPort.BytesToRead < len) { Thread.Sleep(5); } int receivedBytes = serialPort.Read(buffer, 0, buffer.Length);
以上が.NET Micro Frameworkでのシリアル通信の基本になります。
一度ハードウェアを組み立てれば、後はソフトウェアの問題なので、興味のある方はRC-S620Sのコマンドリファレンスマニュアルを読みつつドライバを書いてみてはいかがでしょうか。
Arduino向けのソースコードがありますので、私はこれをベースにNetduino用のドライバを書きました。
今回実装したFeliCa認証システムのソースは、調整ののちBitbucket上で公開予定です。
Netduinoの開発環境を整える
Netduinoとは
簡単に言うとC#で開発のできるマイコンボードです。
.NET Micro Frameworkという小規模組み込み機器用の.NET環境が組み込まれており、Visual Studioで書いたC#プログラムを動作させることができます。
詳しくはこちらを。
準備
Netduinoでの開発を行うためには開発環境を整えなくてはいけません。
まずはこちらより、以下の物をインストールして下さい。
- Microsoft Visual C# Express 2010(上位エディションも可)
- .NET Micro Framework SDK v4.1
- Netduino SDK v4.1.0 (32bit/64bit)
インストールが完了したらVisual Studioを起動してソリューションを作成します。
テンプレートの「Micro Framework」から「Netduino Plus Application」を選んで下さい。
Lチカ
Hello World代わりとしてNetduinoにあるオンボードLEDを点滅させてみます。(Lチカ)
Netduino上のピンやLEDはOutputPortクラスで取得できます。Pins.ONBOARD_LEDを指定してオンボードLEDのオブジェクトを取得し、WriteメソッドでLEDをオン/オフさせます。
using System.Threading; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.NetduinoPlus; namespace NetduinoPlusApplication1 { public class Program { public static void Main() { // オンボードLEDの点滅 OutputPort boardLed = new OutputPort(Pins.ONBOARD_LED, false); boardLed.Write(false); // LED点滅は別スレッドで実行 new Thread(() => { while (true) { boardLed.Write(false); Thread.Sleep(500); boardLed.Write(true); Thread.Sleep(500); } }).Start(); // メインスレッドを終了させるとプログラムが終了するので無限に停止 Thread.Sleep(Timeout.Infinite); } } }
ICS向けAndroidのビルド環境を整える
最近、Galaxy Nexusを手に入れました。
この端末が欲しかった理由は自分専用のカスタムROMを作ること。Android 4.0のリファレンス機だけあって、カスタムROMは作りやすいのです。
とはいえAndroidのソースの入手からビルドを行うのはなかなか困難。
そこでカスタムROM作りの顛末を、自分の備忘録も兼ねてこのブログに残していきます。
あ、お約束ですが注意点。
このブログの記事を真似て端末が起動しなくなった、保証が切れたなどのトラブルが起きても当方では一切責任を負いません。
あくまで自己責任でお願いします。
開発環境
Androidのビルドに使用した環境は次のとおりです。
環境の構築
まずはAndroidをビルドするために必要なアプリケーションやライブラリをインストールします。
基本的にはAOSPのサイトに書いてあるとおりに行いますが、若干手順を変えております。
JDKのインストール
OracleのJDKのサイトより、JDK6をインストールします。記事執筆時のバージョンはJava SE 6 Update 31でしたが、JDK6であれば問題ないと思います。
$ mkdir ~/work $ cd ~/work $ wget http://download.oracle.com/otn-pub/java/jdk/6u31-b04/jdk-6u31-linux-x64.bin $ chmod +x jdk-6u31-linux-x64.bin $ ./jdk-6u31-linux-x64.bin
以下は.bashrcに記述
export JAVA_HOME=~/work/jdk1.6.0_31 export PATH=$PATH:$JAVA_HOME/bin export ANDROID_JAVA_HOME=$JAVA_HOME
sourceコマンドで記述内容を反映
$ source ~/.bashrc
ビルドに必要なパッケージのインストール
コンパイラなど必要なパッケージをaptでインストールします。
$ sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline-gplv2-dev lib32z-dev libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown libxml2-utils xsltproc $ sudo apt-get install libx11-dev:i386
USBの設定
Galaxy Nexus用にUSBの設定をします。
$ sudo vi /etc/udev/rules.d/51-android.rules
51-android.rulesに以下を記述する。OWNERの****の部分は自分のユーザー名を指定
# adb protocol on maguro/toro (Galaxy Nexus) SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="6860", MODE="0600", OWNER="****" # fastboot protocol on maguro/toro (Galaxy Nexus) SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e30", MODE="0600", OWNER="****"
追記後、以下のコマンドを実行する。
$ sudo chmod a+x /etc/udev/rules.d/51-android.rules $ sudo /etc/init.d/udev restart
Android SDKのインストール
adbやfastboot用に必要です。Androidアプリを開発するわけではないので「Android SDK Platform-tools」のみインストールすればOKです。
$ mkdir -p ~/work/android $ cd ~/work/android $ wget http://dl.google.com/android/android-sdk_r16-linux.tgz $ tar xvf android-sdk_r16-linux.tgz $ ./android-sdk-linux/tools/android
.bashrcに以下を追記
export ANDROID_SDK_HOME=~/work/android/android-sdk-linux export PATH=$PATH:$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools
sourceコマンドで記述内容を反映
$ source ~/.bashrc
ccacheの設定
ccacheを使うと、コンパイル結果をキャッシュしてくれるので2回目以降のビルド時間を短縮することができます。
Androidはccacheに対応し
sourceコマンドで記述内容を反映
$ source ~/.bashrc
ているため、環境変数を設定すれば自動でキャッシュしてくれます。
.bashrcに以下を記述
export USE_CCACHE=1
ccacheは通常、~/.ccacheにキャッシュを保存します。ホームディレクトリに置きたくないという場合は、以下の設定をすることでキャッシュの保存先を変更できます。
.bashrcに以下を記述。ここでは/work/ccacheにキャッシュディレクトリを設定します。
export CCACHE_DIR=/work/ccache
sourceコマンドで記述内容を反映
$ source ~/.bashrc
ccacheのキャッシュディレクトリのデフォルトサイズは1GBと小さいため変更する必要があります。
AOSPのサイトでは50〜100Gほど設定するといいとあるので、ここでは50GBを設定します。
ccacheコマンドはAndroidのソースコード内に含まれています。ソースコードのダウンロード後に以下を実行してください。具体的な方法は改めて説明します。
Androidのソースコードのディレクトリへ移動 $ prebuilt/linux-x86/ccache/ccache -M 50G
repoのインストール
ソースコードのダウンロードや管理に利用するrepoをダウンロードします。
$ mkdir ~/bin $ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo $ chmod a+x ~/bin/repo
.bashrcに以下を記述
export PATH=$PATH:~/bin
sourceコマンドで記述内容を反映
$ source ~/.bashrc
以上で環境構築は終わりです。おつかれさまでした。