2011年12月31日土曜日

Android Compatibility PackageでFragmentを楽しむ

Android 3.0より低いバージョンでFragmentを利用する場合は、Android Compatibility
Packageをインストールする必要があります。Android Compatibility Packageは
SDK Managerからインストールすることが可能です。

android-sdk-windows\extras\android\compatibility
以下にファイルが作成されていれば、インストールされています。


1. Android Projectを作成します
2. android-support-v4.jarファイルを適当なところにコピーします
 - android-sdk-windows\extras\android\compatibility\v4にあります
- 例えばlibsフォルダを作成してその下にコピーするなど
3. Eclipseでjarにパスを通します
- プロジェクト名-> Property -> Java Build Path -> Add JARs

<サンプルコード>

試しに、Fragmentのサンプルの簡易版を動かしてみて、Android2.3の
Xperiaで動作することが確認できました。ICSが出る前に先行して開発が
進められそうで便利そうです。

基本のサンプルは、以下のページにあるものをAndroid Compatibility
Packageにあわせて修正したものです。

package jp.gr.java.conf.ulexite.fragmenttest;

import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class TitlesFragment extends ListFragment {
private int mCurCheckPosition = 0;
private static final String[] mTitles = {"Title1", "Title2", "Title3", "Title4",
"Title5", "Title6", "Title7", "Title8"};

@Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);

ArrayAdapter titlesArray = new ArrayAdapter(getActivity(),
R.layout.title, mTitles);
setListAdapter(titlesArray);

if (savedState != null) {
mCurCheckPosition = savedState.getInt("curChoice", 0);
}

getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
}

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}

@Override
public void onListItemClick(ListView l, View v, int pos, long id) {
showDetails(pos);
}

private void showDetails(int index) {
mCurCheckPosition = index;

getListView().setItemChecked(index, true);

// Check what fragment is shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);

// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
FragmentTransaction ft
= getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
}

2011年11月17日木曜日

git --numstat

gitのnumstatがとても便利です。numstatはソースコードの変更行数を出してくれるので、リポジトリの変更がどの程度行われたのか、また、どのファイルが特に変更されたのかなどをざっと見る時にとても便利です。

簡単な使い方としては、git logと組みわせる方法があります。

$ git log --numstat

以下のようなログが出ます。
(https://android.googlesource.com/platform/frameworks/base のログの一つです)

commit 2237e1e7b636651f0ed1efacefa8aaccb21433ca
Author: Eric Fischer
Date: Wed Nov 2 15:14:43 2011 -0700

Import revised translations. DO NOT MERGE
Change-Id: I2f073cc6d62d757ba4e6565a0c7974ca9cecba4c

1 1 core/res/res/values-en-rGB/strings.xml
1 1 core/res/res/values-ru/strings.xml
5 5 core/res/res/values-sw/strings.xml
24 24 core/res/res/values-uk/strings.xml
2 2 packages/BackupRestoreConfirmation/res/values-sw/strings.xml
2 2 packages/SystemUI/res/values-af/strings.xml
1 1 packages/SystemUI/res/values-ru/strings.xml
8 8 packages/SystemUI/res/values-sw/strings.xml
1 1 packages/SystemUI/res/values-uk/strings.xml

この場合だとリソースのみの変更であることが一目でわかります。

またdiffとの組み合わせも便利です。

$ git diff android-2.2_r1 android-2.3.1_r1 --numstat

99 64 Android.mk
21 1 CleanSpec.mk
418795 0 api/9.xml
24489 1485 api/current.xml
0 31 awt/Android.mk
0 1354 awt/com/android/internal/awt/AndroidGraphics2D.java
0 96 awt/com/android/internal/awt/AndroidGraphicsConfiguration.java
0 87 awt/com/android/internal/awt/AndroidGraphicsFactory.java
0 274 awt/com/android/internal/awt/AndroidImageDecoder.java
0 536 awt/com/android/internal/awt/AndroidJavaBlitter.java
0 75 awt/com/android/internal/awt/AndroidNativeEventQueue.java
0 88 awt/com/android/internal/awt/AndroidWTK.java
0 52 awt/com/android/internal/awt/AwtFactory.java
0 66 awt/com/android/internal/awt/ImageOutputStreamWrapper.java
0 681 awt/java/awt/AWTEvent.java
0 47 awt/java/awt/AWTException.java
0 712 awt/java/awt/AWTKeyStroke.java
0 47 awt/java/awt/AWTListenerList.java
0 61 awt/java/awt/AWTPermission.java
0 39 awt/java/awt/ActiveEvent.java
0 166 awt/java/awt/Adjustable.java
0 352 awt/java/awt/AlphaComposite.java
0 2443 awt/java/awt/BasicStroke.java
0 195 awt/java/awt/BufferCapabilities.java
0 990 awt/java/awt/Color.java



2011年10月25日火曜日

【Android】 KeyEventの発行

KeyEventの発行についてまとめておきます。

KeyEventですが、基本的にIWindowManagerにあるinjectKeyEventを呼び出すことで
可能なのですが、残念ながら公開されているインターフェースではなく、リフレクションを
使う方法でしか呼び出しができません。

そこでいろいろ調べていたのですが、Instrumentationクラスを用いることで可能なことが
分かりました。

http://developer.android.com/reference/android/app/Instrumentation.html

InstrumentationクラスにあるsendKeySyncイベントなどを発行することで可能となります。

ただ、上記のAPIは、UIスレッドでは呼び出し不可能なので、別スレッドを作成して、そこから
呼び出す必要があります。以下、適当なコードですけどサンプルを載せておきます。

以下の手順で動作確認できます。

1. Musicをならす
2. 以下のアプリを起動
3. Buttonを押すと、Musicが停止したり、再開したりさせれます。(Play-Pauseキーなので)

全面のActivityにまずKeyEventが発行され、その後、IntentでMusic側に流れている
ことが確認できます。
public class SandBoxActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button b = (Button) this.findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
KeyEventSender sender = new KeyEventSender();
sender.execute(null);
}
});
}

public boolean onKeyDown(int keyCode, KeyEvent event) {
android.util.Log.d("TEMPORARY", "keyCode = " + keyCode);
return super.onKeyDown(keyCode, event);
}

private class KeyEventSender extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
Instrumentation ist = new Instrumentation();
ist.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
return null;
}
}
}