スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

マッシュルームアプリとかキャンディアプリを作ってみた



やっぱりAndroidのIMEはシメジですよね~
いつも大変お世話になっております。

ところで最近の和製Android端末なら赤外線モジュール積んでいるんで、アドレス交換とかも楽ですが、
よく考えなくてもDesireさんにはそんなモノありません(´;ω;`)

で、そうするとどうなるか。

・昔ながらのメールで連絡先送るね~

になります。




よね?

そう、自分の電話番号をマッシュルームで呼び出せば便利じゃね?

ってことで今更ながら、マッシュルームアプリを作ってみました。




細かい詳細はadamrockerさんのサイトへ

まずは、上記サイトを読んだ上で、作ってくれている「MushroomTemplate」を参考に…というかほぼコピーというか…



public class MyInfo extends Activity {

	private static final String ACTION_INTERCEPT = "com.adamrocker.android.simeji.ACTION_INTERCEPT";
	private static final String REPLACE_KEY = "replace_key";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Intent it = getIntent();
		String action = it.getAction();
		// Simejiからの呼び出し
		if (action != null && ACTION_INTERCEPT.equals(action)) {
			replace( _getMyTelNum());

			return;
		}
		//setContentView(R.layout.main);
		finish();
	}


	/**
	 * 元の文字を置き換える
	 * @param result Replacing string
	 */
	private void replace(String result) {
		Intent data = new Intent();
		data.putExtra(REPLACE_KEY, result);
		setResult(RESULT_OK, data);
		finish();
	}

	/**
	 * 自分の電話番号取得
	 * @return 電話番号文字列
	 */
	private String _getMyTelNum(){
		TelephonyManager ts	= null;
		String returnStr	= null;

		// エラーチェックとかはとりあえず無視
		ts = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
		returnStr = ts.getLine1Number();

		return returnStr;
	}

}


もとの文字列を置き換えるもなにも、欲しいのは電話番号だけなので、
入力されてきた文字列なんて無視です。(ぉぃ)
ちゃんと作るなら、メソッド内でエラーチェックしたりなんだりしますが、
メンドイのでその辺も放置

Androidで自分の電話番号を取得する為にはTelephonyManagerを使うため、マニフェストに
・< uses-permission android:name="android.permission.READ_PHONE_STATE" />
の記述(パーミッションの指定)を忘れずに

とりあえず実際に動かしてみます。
とりあえず何か入力する画面にカーソルを合わせ…
01_mush_sample.png

おもむろにシメジボタンを押すと、味気ない標準のアイコンとセンスのないアプリ名Topに出てくるw
02_mush_sample.png

とりあえず押して見るとちゃんと電話番号が!
03_mush_sample.png


流石にこれだけじゃつまんないので、ついでにキャンディー化してみましょう。


public class MyInfo extends Activity {

	// マッシュルーム
	private static final String ACTION_INTERCEPT = "com.adamrocker.android.simeji.ACTION_INTERCEPT";
	private static final String REPLACE_KEY = "replace_key";

	// キャンディ
	private static final String ACTION_INJECTION = "com.adamrocker.android.simeji.ACTION_INJECTION";
	private static final String CANDITATE_KYE = "candidate_key";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Intent it = getIntent();
		String action = it.getAction();
		// Simejiからの呼び出し
		if (action != null && ACTION_INTERCEPT.equals(action)) {
			replace( _getMyTelNum());
			return;

		}else if(action != null && ACTION_INJECTION.equals(action)){
			_canditate();
			return;
		}
		//setContentView(R.layout.main);
		finish();
	}

	// 中略

	/**
	 * 文字配列の返却
	 */
	private void _canditate(){
		ArrayList telnums = null;
		JSONArray jsons = null;
		Intent data = new Intent();
		String myInfo = null;
		String telhead = null;
		String telbody1 = null;
		String telbody2 = null;

		myInfo = _getMyTelNum();

		telhead = myInfo.substring(0, 3);
		telbody1 = myInfo.substring(3, 7);
		telbody2 = myInfo.substring(7, 11);

		telnums = new ArrayList();
		telnums.add(myInfo);
		telnums.add(telhead + "-" + telbody1 + telbody2);
		telnums.add(telhead + "-" + telbody1 + "-" + telbody2);

		jsons = new JSONArray(telnums);
		data.putExtra(CANDITATE_KYE, jsons.toString());

		setResult(RESULT_OK, data);
		finish();//キャンディーを終了して複数の文字をSimejiに渡す
	}

}

上の方のソースにちょっと足して変更しただけ。
あとはマニフェスト上にキャンディ用のインテントフィルタを追加するのを忘れずに


何か入力する画面にカーソルを合わせ…
04_mush_sample.png

おもむろに「+」ボタン(「ま」の下)を押すと、さっきと同じアプリ名がTopに出てくる
05_mush_sample.png

とりあえず押して見ると今度は変換候補に電話番号が!
06_mush_sample.png



とまあ、すごく簡単にIME拡張出来ましたw
これもステキなIMEソフトを無料で提供してくれているadamrockerさんのお陰です。

そしてやっぱりAndroidは面白い。
家でプログラムヤル気になるしね。

どう考えても BREWとかBREWとかBREWとか…は…、家でヤル気になんね~し…
→コンパイル環境も家にはないけど…


テーマ : プログラミング
ジャンル : コンピュータ

tag : android サンプルソース

ロック画面より上にActivityを表示したい!



マーケットにあるステキなメディアプレーヤーさん方
使っていて疑問に思ったのが、どうやってロック画面より上に表示してるんだ?

と思ってググったら見つかったので試してみます。

明日の鍵 「スクリーンロックを解除する方法」
superdry memorandom :-D [memo]Androidアプリ側からスクリーンロックを解除し、画面表示する方法

どうやら、KeyguardManager.KeyguardLockのdisableKeyguard()で、ロック解除。
reenableKeyguard()で再度有効化、のようです。


何も考えず上記ブログで作られていた クラスを丸パクリし、ResumeでgetUnlock/PauseでreleaseUnlockを呼びました。

そして
・アプリ起動
・電源ボタンを押下
・結果として、確かにロック画面より上にActivityが表示される
となりました。




が、所詮丸パクリのため、一連の動作一回目の電源ボタン押下後に、 何もしていないのに液晶が明るくなって、Activityが表示されます。
二回目以降は問題ないのですが…

どうやら、起動直後のOnResume時にWakelock.acquire(); を読んでいるのが駄目なようです。

ログを見るかぎりは
・起動直後のOnResumeでacquire()(※)
・電源ボタン押下時のOnPauseで、Wakelock.release()
と呼ばれているのにも関わらず、その後
・なぜかOnResumeが走る
なんでかは分からないけど※の処理がスタックされていて、OnPauseの直後に呼ばれているのだろう…

なので借り物のクラスをキーロック時のみacquireを呼ぶように修正
これでとりあえずはOKでした。


  public void getUnlock() {
    // acquire wake lock
    _log("getUnlock:called");
    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mWakelock =
      pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
          PowerManager.ACQUIRE_CAUSES_WAKEUP |
          PowerManager.ON_AFTER_RELEASE, "ScreenLockManager");
    // 今回の呼び出し環境だと、ここにあると困る
    //mWakelock.acquire();

    // unlock screen
    KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    mKeyguardLock = km.newKeyguardLock("ScreenLockManager");
    if (km.inKeyguardRestrictedInputMode()) {
      //ここに移動
      mWakelock.acquire();
      mKeyguardLock.disableKeyguard();
      isScreenLock = true;
      _log("getUnlock: disableKeyguard");
    } else {
      isScreenLock = false;
    }
  }


と、ここまでやってみて一つの疑問が。
PowerManagerでWakeLockを制御する必要は本当にあるのか??
ってことです。

上記以外にも、画面を明るくするために…として呼んでいるソースを見かけるのですが、
そもそも
・スリープ(というのかな?画面暗転)状態で電源ボタン押下すれば、そもそも明るくなる
わけで…

というわけでPowerManager.WakeLock関連全コメントアウトして試してみました。


結果として、何の問題もありませんでした…
個人的には、何故か暗転したままってのを期待したのですが、普通に動いてしまった…


package com.omokageru.ak.screenunlocktest;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;

public class ScreenUnlockTest extends Activity {
  private ScreenLockManager slm = null;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    _log("onCreate");
    slm = new ScreenLockManager(this);
  }

  @Override
  protected void onDestroy() {
    // TODO 自動生成されたメソッド・スタブ
    super.onDestroy();
    _log("onDestroy");
  }

  @Override
  protected void onPause() {
    // TODO 自動生成されたメソッド・スタブ
    super.onPause();
    _log("onPause");
    slm.releaseUnlock();
  }

  @Override
  protected void onResume() {
    // TODO 自動生成されたメソッド・スタブ
    super.onResume();
    _log("onResume");
    slm.getUnlock();
  }

  private void _log( String str){
    Log.d("ScreenUnlockTest Activity", str);
  }
}


/**
 * 以下パクリもの
 */
class ScreenLockManager {

  private Context mContext;
  private KeyguardManager.KeyguardLock mKeyguardLock;
  private boolean isScreenLock;

  public ScreenLockManager(Context context) {
    mContext = context;
  }

  public void getUnlock() {
    _log("getUnlock:called");

    // unlock screen
    KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    mKeyguardLock = km.newKeyguardLock("ScreenLockManager");
    if (km.inKeyguardRestrictedInputMode()) {
      //ここに移動
      mKeyguardLock.disableKeyguard();
      isScreenLock = true;
      _log("getUnlock: disableKeyguard");
    } else {
      isScreenLock = false;
    }
  }

  public void releaseUnlock() {
    _log("releaseUnlock:called");
    // release screen
    if (isScreenLock) {
      mKeyguardLock.reenableKeyguard();
      isScreenLock = false;
      _log("releaseUnlock: reenableKeyguard");
    }
  }

  private void _log(String str){
    Log.d("ScreenLockManager", str);
  }

}


う~ん、ロック解除に関してPowerManagerの利用はどんな意味があるのだろう?
もうちょっと(覚えていたら)調べてみようかな


テーマ : プログラミング
ジャンル : コンピュータ

tag : android サンプルソース

Desire入手!



じゃじゃ~ん、というほどのものでもありませんが、Desire入手しました。
会社名義で。


desire


主な比較対象がHT-03Aなので、比較するのも申し訳ない感じですが、非常に良い感じ。
そのほか会社に転がっているXperiaと比較しても断然Desireですね。
ただ、ハードの作り込みは中の人曰くXperiaのほうがずっと良く出来ており、何かのベンチマークではXperia >> Desireらしいです。
もしかすると、いつ来るかわからないアップデートでXperiaの評価が凄く上がるかもしれません。
ただ、普通の使い勝手とか考えると、やっぱりXperiaという選択肢は無いように思えます。
もし現状でAndroid端末が欲しいならDesire一択ですね。
もしくは次の製品を待つ!
スマートフォンが欲しいならiPhoneなのかな…
まあ、私林檎製品買う気ないのであれですけど…


そういえばXperiaのドライバってダウンロードできるようになったんかな?
4月末の時は公式から消えていた気がするけど、現状はどうなんでしょ? ちなみにDesireの場合は、 HTC SyncってのをPCにインストールし、DesireをPCに繋いで、DesireからHTC sync を選択すればインストールされます。(XP sp3で確認)
ただ、なんかDesire側は接続出来なかったよ!とか言ってきますが、ドライバはインストールされるようです。
インストール後はADBを通じてちゃんと認識されていました(eclipseにて確認)


え?あいえすぜろいち?なにそのメガネケース?


テーマ : グーグルモバイル
ジャンル : 携帯電話・PHS

tag : android

今更ながらDesireを見てきた











最近全く家でプログラム書いてない…
まあ、その分会社で書いているので問題ないですがwww

さて、今日何となく電気屋に行ってフラっと立ち寄ったら
HTC Desire が置いてあり、触れました^^

先日OS2.2もGoogleIOで発表されたので、何処と無く今更感がありますが…


正直な感想

Desire >>>>>>>> Xperia >= HT-03A

です。

XperiaもHT-03Aも(会社名義ですが)保有しています。
もちろんXperiaのハードスペックには全く不満はありません。
CPUだってXperiaとDesireは同じスナップドラゴン。

だけど体感が全然違う、比べるのも失礼なくらい違う。

HT-03Aは既にちょっと前の携帯なので、比較に入れるのはどうかと思いますが、
まあ、メインで使っているので…

個人的に一番使っている(使い慣れている)というのもあり、
Xperia >= HT-03A としました。
正直、普段使うようなアプリでの動作感の差は、XperiaとHT-03Aでそんなに違うとは思えません。

そこを踏まえると、やはりOSのバージョンの差が大きい気がします。
XperiaもわざわざあそこまでOSをカスタマイズするメリットがあるのか気になります。
docomoというキャリアが問題なのか、ソニエリが問題なのか。
PCを買う時だって、(ハードスペックは十分なのに)OSを選択するのに今更98やXPを選ばず、7選ぶでしょ?
iPhone買う時だって今更3G買わずに3GS買うでしょ?(アップル商品買った事ないけど)
1.6を選ぶ理由は無いと思うんですけどねぇ…
なんだか時代遅れですよね。
(もちろんセキュリティ的な問題や、キャリアの基準等あるんでしょうが。)

iPhoneは使ったこと無いので、想像で勝手に比較するとこんな感じでは?

Desire > iPhone 3GS >>>>>>>> Xperia >= HT-03A

Android 2.2 は更に速度向上とのことですので、今後が更に気になります。
HTC EVO 出ないかな~

来月には次世代iPhoneの発表があるはずですし、スマホ市場の行方は気になりますね。



え?IS-01?
なにそのキャベツロイド。

テーマ : グーグルモバイル
ジャンル : 携帯電話・PHS

tag : android

特定のタップイベント時にMapViewから座標を取得する



意外と試行錯誤したので記録にしておきます。


というワケでまずは特定のタップイベントの取得に関して・・・。
は、以下のサイトを参考にしました。
hoge256blogさん
adakodaさん


上記のサイトを見て、なんも考えずに
・Activity → MapActivity
ぐらいの変更でとりあえずなんとかなるだろう・・・。
ってのがまず甘かった。


public class Main extends MapActivity implements
	GestureDetector.OnGestureListener,
	GestureDetector.OnDoubleTapListener {

	private GestureDetector gesture;
	private MapView mapView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		protected void onCreate(Bundle icicle) {
		// TODO 自動生成されたメソッド・スタブ
		super.onCreate(icicle);
        setContentView(R.layout.main);

        mapView = (MapView)findViewById(R.id.map);
		mapView.setEnabled(true);
		mapView.setClickable(true);
		mapView.setBuiltInZoomControls(true);
		mapView.setSatellite(false);
		
		gesture = new GestureDetector(this);

		mapView.invalidate();

	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		gesture.onTouchEvent(event);
		return super.onTouchEvent(event);
	}
	// 以下onDoubleTapとか軒並み略

いわずともあれです。
MapView上をタップしても「onTouchEvent」にイベントが来ません。
上記には書いていませんが、ところ狭しとログかけまくってます。
MapViewが全て処理してくれているため、当たり前といえば当たり前です。


じゃあ、上記mapViewになんかタッチを処理しそうなリスナーとか登録すりゃいいんじゃね?
と考え、eclipseの力を発揮(?)させ、setOnTouchListenerなるものを発見。
ってことで以下に修正。


public class Main extends MapActivity implements
	GestureDetector.OnGestureListener,
	GestureDetector.OnDoubleTapListener {

	private GestureDetector gesture;
	private MapView mapView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		protected void onCreate(Bundle icicle) {
		// TODO 自動生成されたメソッド・スタブ
		super.onCreate(icicle);
        setContentView(R.layout.main);

        mapView = (MapView)findViewById(R.id.map);
		mapView.setEnabled(true);
		mapView.setClickable(true);
		mapView.setBuiltInZoomControls(true);
		mapView.setSatellite(false);
		
		gesture = new GestureDetector(this);
		
		// 追加
		mapView.setOnTouchListener( new OnTouchListener() {
			
			public boolean onTouch(View v, MotionEvent event) {
				// TODO 自動生成されたメソッド・スタブ
				gesture.onTouchEvent(event);
				return false;
			}
		});

		mapView.invalidate();

	}

/*	コメントアウト
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		gesture.onTouchEvent(event);
		return super.onTouchEvent(event);
	}
*/
	// 以下onDoubleTapとか軒並み略

結果、一回しかイベント取れないし。
ちょっとやってみたところ、どうやら「onTouch」で一度でもfalseを返すともうダメ。
普通false返したら、superクラスというか、そもそも備えた処理してくれるんじゃないんですか。
自前で処理を全部書いて、全てtrueを返すなら運用出来そうですが、MapViewですよ。
もともとある機能の分まで実装できるかっての。
ていうかできるくらい能力ありゃ苦労しませんよねw


そこで考えたのが、「流石にイベントが来ていない訳ないだろ」ということ。
横取りしちまえwwww ってこの辺の発想はVCのサブクラス化とかから来てるのかな・・・。
ということで次のように修正。



	// 略
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		// TODO 自動生成されたメソッド・スタブ
		gesture.onTouchEvent(ev);
		return super.dispatchTouchEvent(ev);
	}
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		
		//略
		
/*	コメントアウト
		// 追加
		mapView.setOnTouchListener( new OnTouchListener() {
			
			public boolean onTouch(View v, MotionEvent event) {
				// TODO 自動生成されたメソッド・スタブ
				gesture.onTouchEvent(event);
				return false;
			}
		});
*/
		mapView.invalidate();

	}

	// 以下onDoubleTapとか軒並み略

あくまでイベントが知りたいだけなので、処理するしないに関わらず、本来の処理に渡しています。
こうすることで
・イベント取れる
・MapViewそのものの処理は邪魔しない(はず)
と考えました。


だが幸せは長く続かなかった


とりあえず長押し処理に何かを付け加えましょう。
わかりやすいので長押しした場所を中央に移動するとかにしました。


	public void onLongPress(MotionEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		// 以下を追加
		// タップされた画面座標をmapView上の緯度経度に変換
		GeoPoint temp = mapView.getProjection().fromPixels((int)e.getX(), (int)e.getY());
		_log("GeoPoint lat:" + temp.getLatitudeE6() + " long:" + temp.getLongitudeE6());
		mapView.getController().animateTo(temp);
		mapView.postInvalidate();
	}

こちらも一見良さそうですが、良く考えるとmapViewに渡している画面座標って、たぶんMapActivityが管理している幅になりますよね。
当然これ動作させると、なんだか長押しした場所がView中央よりやや北側になります。
ちなみに以下のような画面ならなおのこと・・・。


この場合富士山を長押ししたところで、富士山がView中央にくることはない。
device20100214.png


じゃあ、あとは何があるかと考えると、
・MapViewを拡張する
くらいかなと思っていたところでこんなのを発見
日本アンドロイドの会
該当ページの一番下の方で「タップされた位置にアイコンを描画する」って項目があるじゃないですか。
しかも後で気がついたんですがAndroidプログラミング入門にもそれっぽいこと書いてあるし・・・。一体どこ読んでんだ?っていわれそうです。
ってことでOverlayを試してみましょう。


public class Main extends MapActivity {

	private MapView mapView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		protected void onCreate(Bundle icicle) {
		// TODO 自動生成されたメソッド・スタブ
		super.onCreate(icicle);
        setContentView(R.layout.main);

        mapView = (MapView)findViewById(R.id.map);
		mapView.setEnabled(true);
		mapView.setClickable(true);
		mapView.setBuiltInZoomControls(true);
		mapView.setSatellite(false);
		mapView.getOverlays().add( new MyOverlay(mapView));
		mapView.invalidate();

	}
	
	/*略*/
}

/**
 * Overlayクラス追加
 */
class MyOverlay extends Overlay implements
	GestureDetector.OnDoubleTapListener,
	GestureDetector.OnGestureListener{

	private GestureDetector gesture = new GestureDetector(this);
	private MapView parent;

	MyOverlay(MapView mapView){
		parent = mapView;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent e, MapView mapView) {
		// TODO 自動生成されたメソッド・スタブ
		gesture.onTouchEvent(e);
		return super.onTouchEvent(e, mapView);
	}
	
	
	/* 略 */
	
	public void onLongPress(MotionEvent e) {
		// TODO 自動生成されたメソッド・スタブ
		GeoPoint temp = parent.getProjection().fromPixels((int)e.getX(), (int)e.getY());
		parent.getController().animateTo(temp);
		parent.postInvalidate();

	}
	
	/* 略 */
	
}

これで無事MapView上で長押しした場所が、Viewの真ん中に来ることになりました。
まさかOverlayにこんな使い方があるとは・・・。
てっきり描画だけかと思っていましたし。
いや、正しい使い方かどうかは分かりませんがね。
まあ、考え方によってはイベント処理のみを追加したい場合に、こんなOverlayクラスを追加するだけでできるので、既存の処理への影響が少ない!かもしれないというメリットがありますかね?


テーマ : グーグルモバイル
ジャンル : 携帯電話・PHS

tag : android サンプルソース

プロフィール

駄猫

Author:駄猫

Twitter
その他
最新記事
カテゴリ
月別アーカイブ
検索フォーム
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。