2011年3月10日木曜日

ListViewをカスタマイズする

ListViewをカスタマイズする

ここが参考になりすぎて、自分で書くことがないのですが、とりあえずメモがわりとして。
実際に動かして表示したコードは、またいつか気が向いたら。

TwitterのTimelineを表示するのはほとんどこれでできちゃいました。
本当は、過去分とかはキャッシュしたりしてsqliteとかに放りこみたいのですが、
スポットでTimeline表示するだけならこれで十分かと。

Twitter Clientとかでよくある、30min agoとか何分前とか。"elapsed time"

これもライブラリがありました。
prettytimeだって。

Convert elapsed timestamps, like, “in 3 minutes!”
elapsed time = 経過時間 というらしい。(恥

ocpsoft-pretty-time-1.0.6.jarを使用しました。

Dateにフォーマットかけて
TextViewにセットするだけです。

  1. PrettyTime p = new PrettyTime();  
  2. String prettyTime = p.format(*DateClassのインスタンス*);  
  3. TextView minutetext = (TextView)view.findViewById(R.id.minutetext);  
  4. minutetext.setText(prettyTime);  

簡単簡単。

Twitter4j でプロフィールのイメージを表示

先の投稿、Twitter4jでxAuth認証 で作成した、TwitterWrapperを使用しています。

Activityの中で。

  1. TwitterWrapper twa = new TwitterWrapper();  
  2.         // TwitterWrapperに用意してあるmethodで、SharedPreferencesに保存してあるTwitterの  
  3.         // oAuth Token と oAuth Token Secretを使って、アカウントをログイン状態にしています。  
  4.         twitter = twa.getAuthorizedTwitter(this);  
  5.           
  6.         // SharedPreferencesに保存しておいた、設定を取得  
  7.         SharedPreferences pref =   
  8.             getSharedPreferences(Values.TWITTER_PREFERENCE_NAME, Activity.MODE_PRIVATE);  
  9.         // SharedPreferencesに保存しておいた、ScreenNameを取得  
  10.         String screenName = pref.getString(Values.TWITTER_ID_KEY,"NONE");  
  11.           
  12.         try {  
  13.             // ScreenNameをつかって、Userのデータを取得。  
  14.             User user = twitter.showUser(screenName);  
  15.             // ScreenNameをつかって、UserのProfile画像のURLを取得。  
  16.             URL imageURL = user.getProfileImageURL();  
  17.             Bitmap profile = null;  
  18.             // これは、適当にViewのLayoutファイルと紐付けしてください。  
  19.             ImageView imgv = (ImageView)findViewById(R.id.userIcon);  
  20.             try {  
  21.                 // BitmapFactory.decodeStreamでビットマップを作成。  
  22.                 profile = BitmapFactory.decodeStream(  
  23.                     imageURL.openConnection().getInputStream());  
  24.                 if ( profile != null ) {  
  25.                     // ちゃんと画像が取得できた時だけ、ImageViewにせってい  
  26.                     imgv.setImageBitmap(profile);  
  27.                 }  
  28.             } catch (IOException e) {  
  29.                 // 取れなかったら無視、レイアウトファイルに  
  30.                 // デフォルト画像のsrcを設定しておくとそれが出ます。  
  31.             }  
  32.               
  33.         } catch (TwitterException e) {  
  34.             e.printStackTrace();  
  35.         }  

2011年3月9日水曜日

Twitter4jでxAuth認証

実際にActivityに書いて認証を呼び出すコードを。

めんどくさいので、TwitterWrapperというクラスを作りました。
設定値は、Valuesというクラスに入れてあります。(手抜き

ステップは4つ
1)twitter4jのjarファイルをビルドパスに追加。
2)設定用のValuesクラスを用意。
3)TwitterWrapperを用意。
4)Activityにメソッドを記述。

1)twitter4jのjarファイルをビルドパスに追加。
これは適当にどこか見てみてください。
こことか。JavaでTwitterをOAuth認証して使えるTwitter4jとは

Versionは、twitter4j-android-2.2.1-SNAPSHOT.zip を使用しました。
他必要なライブラリは、oauth-signpost で、signpost-commonshttp4-1.2.1.1.jar とsignpost-core-1.2.1.1.jarです。

2)設定用のValuesクラスを用意。
設定用のValuesクラス
  1. public class Values {  
  2.   
  3.  public static final String TWITTER_SCREEN_NAME = "じぶんのアカウント";  
  4.    
  5.  public static final String TWITTER_CONSUMER_KEY = "自分のConsumerKey";  
  6.  public static final String TWITTER_CONSUMER_SECRET = "自分のConsumerSecret";  
  7.  public static final String TWITTER_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token";  
  8.  public static final String TWITTER_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";  
  9.  public static final String TWITTER_CALLBACK_URL = "http://てけとうに自分のサイト/";  
  10.  public static final String TWITTER_PREFERENCE_NAME = "おすきに";  
  11.    
  12.  public static final String TWITTER_ID_KEY = "screen_name";  
  13.  public static final String TWITTER_TOKEN_KEY = "token";  
  14.  public static final String TWITTER_TOKEN_SECRET_KEY = "tokenSecret";  
  15.    
  16.  public static final String TWITTER_ACCESS_TOKEN_KEY = "accessToken";  
  17.    
  18. }  

3)TwitterWrapperを用意。


インポート文
  1. import twitter4j.Query;  
  2. import twitter4j.QueryResult;  
  3. import twitter4j.Tweet;  
  4. import twitter4j.Twitter;  
  5. import twitter4j.TwitterException;  
  6. import twitter4j.TwitterFactory;  
  7. import twitter4j.User;  
  8. import twitter4j.conf.Configuration;  
  9. import twitter4j.conf.ConfigurationBuilder;  
  10. import twitter4j.http.AccessToken;  
  11. import twitter4j.http.OAuthAuthorization;  
  12. import java.util.List;  
  13. import android.app.Activity;  
  14. import android.content.SharedPreferences;  
  15. import android.util.Log;  
  16. import android.widget.EditText;  
  17.   
  18. // リソースファイルがわり。  
  19. import jp.mediba.android.util.Values;  

クラス
  1. public class TwitterWrapper {  
  2.     Twitter twitter;  
  3.    
  4.     public TwitterWrapper() {  
  5.         // do nothing  
  6.     }  
  7.   
  8.     public TwitterWrapper(Twitter twitter) {  
  9.         this.twitter = twitter;  
  10.     }  
  11.    
  12.     public Twitter getTwitter() {  
  13.         return twitter;  
  14.     }  
  15.   
  16.     public void setTwitter(Twitter twitter) {  
  17.         this.twitter = twitter;  
  18.     }  
  19.    
  20.     /** 
  21.      * Usage: java twitter4j.examples.search.SearchTweets [query] 
  22.      */  
  23.     public List<tweet> searchTweet() {  
  24.         String str = Values.TWITTER_HASHTAG;  
  25.         Twitter twitter = new TwitterFactory().getInstance();  
  26.         try {  
  27.             Query query = new Query(str);  
  28.             query.setRpp(30);  
  29.             QueryResult result = twitter.search(query);  
  30.             List<tweet> tweets = result.getTweets();  
  31.             return tweets;  
  32.         } catch (TwitterException te) {  
  33.             te.printStackTrace();  
  34.             Log.w("TWT""Failed to search tweets: " + te.getMessage());  
  35.         }  
  36.         return null;  
  37.     }  
  38.       
  39.     public void authorization(Activity act) throws TwitterException {  
  40.        
  41.         ConfigurationBuilder builder =  
  42.                 new ConfigurationBuilder();  
  43.         builder.setOAuthConsumerKey(Values.TWITTER_CONSUMER_KEY);  
  44.         builder.setOAuthConsumerSecret(Values.TWITTER_CONSUMER_SECRET);  
  45.         TwitterFactory factory = new TwitterFactory(builder.build());  
  46.         String screen_name =   
  47.                 ((EditText)act.findViewById(R.id.txtScreenName)).getText().toString();  
  48.         String password =   
  49.                 ((EditText)act.findViewById(R.id.txtPassword)).getText().toString();  
  50.         Twitter twitter = factory.getInstance(screen_name,password);  
  51.         AccessToken accessToken = null;  
  52.         try {  
  53.             accessToken = twitter.getOAuthAccessToken();  
  54.             String token = accessToken.getToken();  
  55.             String tokenSecret = accessToken.getTokenSecret();  
  56.             SharedPreferences pref =   
  57.                 act.getSharedPreferences(  
  58.                     Values.TWITTER_PREFERENCE_NAME,  
  59.                     Activity.MODE_PRIVATE);  
  60.             SharedPreferences.Editor editor = pref.edit();  
  61.             editor.putString(Values.TWITTER_TOKEN_KEY,token);  
  62.             editor.putString(Values.TWITTER_TOKEN_SECRET_KEY,tokenSecret);  
  63.             editor.putString(Values.TWITTER_ID_KEY,screen_name);  
  64.             editor.commit();  
  65.         } catch (TwitterException e) {  
  66.             e.printStackTrace();  
  67.             throw e;  
  68.         }  
  69.     
  70.     }  
  71.   
  72.       
  73.     public Twitter getAuthorizedTwitter(Activity act) {  
  74.         SharedPreferences settings =   
  75.             act.getSharedPreferences(Values.TWITTER_PREFERENCE_NAME, 0);  
  76.         String token = settings.getString(Values.TWITTER_TOKEN_KEY,"NONE");  
  77.         String tokenSecret = settings.getString(Values.TWITTER_TOKEN_SECRET_KEY,"NONE");  
  78.        
  79.         Twitter twitter = new TwitterFactory().getInstance();  
  80.         if(twitter.getAuthorization().isEnabled()){  
  81.             return twitter;  
  82.         } else {  
  83.             ConfigurationBuilder builder = new ConfigurationBuilder();  
  84.             builder.setOAuthConsumerKey(Values.TWITTER_CONSUMER_KEY);  
  85.             builder.setOAuthConsumerSecret(Values.TWITTER_CONSUMER_SECRET);  
  86.             builder.setOAuthAccessToken(token);  
  87.             builder.setOAuthAccessTokenSecret(tokenSecret);  
  88.             Configuration configuration = builder.build();  
  89.   
  90.             TwitterFactory factory = new TwitterFactory();  
  91.             try {  
  92.                 twitter = factory.getInstance(new OAuthAuthorization(configuration));  
  93.             } catch (java.lang.StringIndexOutOfBoundsException e) {  
  94.                 return null;  
  95.             }  
  96.            
  97.             if(twitter.getAuthorization().isEnabled()){  
  98.                 return twitter;  
  99.             } else {  
  100.                 return null;  
  101.             }  
  102.         }  
  103.     }  
  104. }  

4)Activityにメソッドを記述。

Activityに以下のメソッドを書きます。

インポート文
  1. import twitter4j.TwitterException;  
  2. import jp.mediba.android.util.TwitterWrapper;  

Activityに以下のメソッドを書き、ボタンに結びつけます。

  1. public void pushAuth(View v) {  
  2.         TwitterWrapper tw = new TwitterWrapper();  
  3.         AlertDialog.Builder abuilder = new AlertDialog.Builder(this);  
  4.         try {  
  5.          // ActivityそのものをTwitterWrapperに渡しています。  
  6.    tw.authorization(this);  
  7.    // 設定が完了したら、ダイアログを出す。  
  8.    abuilder.setMessage( R.string.dialog_api_twitter_setting_done_title )  
  9.           .setCancelable(false)  
  10.           .setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {  
  11.               public void onClick(DialogInterface dialog, int id) {  
  12.                dialog.cancel();  
  13.                // ダイアログのOKをおしたら、別画面に遷移。  
  14.                goTweet();  
  15.               }  
  16.           });  
  17.      
  18.   } catch (TwitterException e) {  
  19.    e.printStackTrace();  
  20.    // なんかエラーが起きたら、ダイアログを出す。  
  21.    abuilder.setMessage( R.string.error_api_twitter_login )  
  22.          .setCancelable(false)  
  23.          .setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {  
  24.              public void onClick(DialogInterface dialog, int id) {  
  25.               dialog.cancel();  
  26.              }  
  27.          });  
  28.     
  29.   }  
  30.   AlertDialog alert = abuilder.create();  
  31.   alert.show();  
  32.     }  
  33.       
  34.     // 遷移したいActivityをセットして、画面遷移するロジックは外出ししておく。  
  35.     public void goTweet() {  
  36.      Intent intent = new Intent(this, ActTweet.class);  
  37.      startActivity(intent);  
  38.      finish();  
  39.     }  
  40.       

Twitter xAuth申請で疲れた…。

Androidにて、Twitter連携アプリを作成し、xAuthに対応させてみました。
その際、xAuthの申請で、非常に時間がかかったので、まとめ。

最初、アプリケーション名と、情報だけ書いて、開発中ですとメール送ったら、
これでできない?「http://dev.twitter.com/pages/oauth_single_token
とお返事が帰ってきました。
先に、oAuthのTokenとTokenSecretをとっておいて、アプリに埋め込んじゃえばoAuthで投稿できるよという意味らしいです。



しかしこれでは、アプリでユーザーがログインして、そのアカウントで投稿するってのができません。

xAuthの許諾は真面目に審査してるみたいです。
開発目的での許諾は行わないとのメールももらいました。

ということで、xAuthの許可を得るのに必要な準備事項をまとめておきます。

1)oAuthアプリケーションの登録。
Webでは下記の場所から登録できます。
「設定」>「連携アプリ」>「連携アプリの追加と設定は『こちら』から変更できます。」
2)アプリのログイン画面とTweet画面、TLの画面をキャプチャしてPDFか何かで、説明文をまとめたもの。
Twitterのチケットサーバーは添付ファイルに対応していないようなので、PDFや画像はどこか公開できるサーバーに配置しておきましょう。


この状態で、以下のメールをapi@twitter.comにおくります。
(英文が変なのは、気にしないでください。www )

---
Hello.

I'm a developer of "アプリケーション名".

"アプリケーション名" is a android application, for tweeting some messages.
I want to use this application for a multi users' twitter client.
I do not want to use android.webkit.WebView because of Userbility.
I send this application screen capture and explain the reason of using xAuth.
URL:{スクリーンキャプチャのURLとか。}
Please apply this app to use xAuth.

Application Name: {アプリケーション名}
App Source Code : (now developping)
My account : @{ツイッターのスクリーンネーム}
oAuth Clients : http://twitter.com/oauth_clients/details/{oAuth申請のページのID}

Thank you.
---


これで一発で通るはず。

あとは、Twitterにログインした状態で、
のステータスを確認していましょう。

ちなみに、なんでWebViewを使わないか、ってところの文章は、「日本人アンドロイドに慣れてないの。」としていましたが、これさすがに汎用的に使われると如何かと思うので、文章を「because of Userbility.」に変えてあります。

申請の際に仕様した、PDFも少々変えてありますが、添付しておきます。
(多分ちゃんとしたスクリーンキャプチャのほうが、いいはず。)

2011年2月22日火曜日

au IS04 (REGZA Phone) がADBでデバイス認識されない(MAC OS10.6.6)

タイトルの通りですが、MAC OSXでのAndroid開発環境では、通常は端末をデバッグモードでUSB接続した場合、とくにドライバのインストール作業などを行わずに使用することができました。

(過去に問題なく接続できた端末)
・HTC HT03A
・HTC Desire
・SonyEricsson EXPERIA
・SHARP IS01
・SHARP IS03

今回、TOSHIBA IS04 で実機検証する機会があり、今までと同じようにUSB接続してみたところADB上で認識されません。

WEB上で色々と調べた結果、以下の方法で解決したのでまとめておきます。

1.  .androidディレクトリ(だいたいはユーザディレクトリの直下にあります)
にadb_usb.iniというファイルがあるか確認

2. なければ adb_usb.ini の作成
こちらのサイトを参考にさせていただきました。
http://d.hatena.ne.jp/rmiya/20091109

3. adb_usb.ini にIS04のベンダーID
0x0930
を追加

4. ADBを再起動

端末を接続し、 adb devices コマンド、またはEclipeなどのUI上で端末が表示されれば成功です。


ちなみに、Windows向けにはドライバが配布されているようです。

2011年1月28日金曜日

Android開発 - 画面の縦横を検知して回転するボタンを作る(3)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)
Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

Javaのコードは2種類
・Main.java (メインのアクティビティクラス)
・AnimationController.java (回転アニメーションの制御)
になります。


AnimationController.java

import android.hardware.SensorEvent;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class AnimationController {

boolean yoko = false;
float touchY;
long ANIM_ROTATE_SPEED = 200;

public void rotateCube(SensorEvent event, ImageButton[] img) {


if (!yoko && event.values[2] > 60 && event.values[2] < 80) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(0, 90, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = true;
}


if (yoko && event.values[2] > -10 && event.values[2] < 10) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(90, 0, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = false;
}
}
}



Main.java



import java.util.List;


import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class Main extends Activity implements SensorEventListener, OnClickListener{

AnimationController animationController = new AnimationController(); 

SensorManager mSensorManager = null;
private boolean mRegisteredSensor;
float touchY;
float moveY;
boolean yoko = false;
RotateAnimation rotateAnimation;


ImageButton button01;
ImageButton button02;
ImageButton button03;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mRegisteredSensor = false;


button01 = (ImageButton)findViewById(R.id.button01);
button02 = (ImageButton)findViewById(R.id.button02);
button03 = (ImageButton)findViewById(R.id.button03);
    }


@Override
protected void onResume() {

List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if (sensors.size() > 0) {
Sensor sensor = sensors.get(0);
mRegisteredSensor = mSensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
}
super.onResume();
}


@Override
protected void onPause() {

if (mRegisteredSensor) {
mSensorManager.unregisterListener(this);
mRegisteredSensor = false;
}
super.onPause();
}


@Override
protected void onStop() {

mSensorManager.unregisterListener(this);
super.onStop();
}


@Override
public void onClick(View v) {


switch( v.getId() ){
case R.id.button01:
//ボタンタッチ時の処理
break;
case R.id.button02:
//ボタンタッチ時の処理
break;
case R.id.button03:
//ボタンタッチ時の処理
break;
}
}


@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}


@Override
public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {


ImageButton[] img = {button01,button02,button03};
animationController.rotateCube(event, img);
}
}
}



Main.java の onSensorChanged → Sensor.TYPE_ORIENTATIONで傾きを検知し、SensorEvent と 対象となるボタンを AnimationController に渡しています。

センサーイベントの event.values[2] でY軸の傾きの値が取れます。
event.values[2] = 60〜80 でボタンを横向きに、
event.values[2] = -10〜10 でボタンを縦向きにアニメーションさせていますが、このあたりの設定は改善の余地がありそうです。



センサーイベントの実装は、以下のサイトを参考にさせていただきました。
http://www.adakoda.com/android/000182.html