Social Icons

2013年2月16日 星期六

Google Map Key - 您輸入的指紋無效

申請Google Map Key卻出現,對不起您輸入的指紋無效? 最近重新申請Google Map Key,照往例用keytool列出debug.keystore的憑證指紋,卻沒想到在申請頁面一直出現『您輸入的指紋無效;請按瀏覽器的 [上一頁] 按鈕,並輸入有效的憑證指紋。』的訊息。沒錯啊,整個過程都沒錯啊,怎麼會這樣? 後來看到檢察了一下發現奇怪我的key怎麼特別的長?才發現原來申請Google Map Key的憑證指紋要是MD5的,

而keytool列出來的是SHA1,
 

怎麼會這樣呢?以前都沒有問題啊!原來最近將JDK升級到版本7。結果呢!在版本7的keytool預設的輸出是SHA1,我的嗎啊!怎麼會這樣呢?需不需要降級到版本6啊?還好查了一下,只要在執行時加上 -v 這個參數就可以將所有編碼的憑證指紋都列出來了。

下回還是不要亂升級了,會搞死人的。 :)

兩個View切換中,如何產生平滑效果

因為目前在開發的程式中,有許多視窗,而使用者需要在這些視窗中切換,為了讓程式跑的順一點,並沒有create很多的activity,而是透過且切換View來達成。 但是在View切換過程,如果是使用動畫來表現的話,應該是比較好看的,所以趁這個機會研究一下Android的動畫,這邊要講的是如何在不同View之間,產生平滑移動的小效果。 首先,我們先建立幾個動畫XML檔(請放在/layout目錄下) left_in.xml
<?xml version="1.0" encoding="utf-8"?>   
<set 
        xmlns:android="http://schemas.android.com/apk/res/android">   
    <translate 
            android:fromXDelta="-100%p" 
            android:toXDelta="0"  
        android:duration="500" />   
  
</set>
left_out.xml
<?xml version="1.0" encoding="utf-8"?>   
<set 
    xmlns:android="http://schemas.android.com/apk/res/android">   
    <translate 
            android:fromXDelta="0" 
            android:toXDelta="-100%p"  
        android:duration="500" />
</set>
right_in.xml
<?xml version="1.0" encoding="utf-8"?>   
<set 
        xmlns:android="http://schemas.android.com/apk/res/android">   
    <translate 
            android:fromXDelta="100%p" 
            android:toXDelta="0"  
        android:duration="500" />   
  
</set>
right_out.xml
<?xml version="1.0" encoding="utf-8"?>   
<set 
    xmlns:android="http://schemas.android.com/apk/res/android">   
    <translate 
            android:fromXDelta="0" 
            android:toXDelta="100%p"  
        android:duration="500" />
</set>
在main.xml我們定義了兩個Views,一個一開始是顯示的,另一個是隱藏起來的,另外定義了兩個按鈕來做視窗的切換。
.....
     <LinearLayout
      android:id="@+id/map_view"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
   android:layout_marginTop="0dip"
   android:layout_marginBottom="0dip"
   android:layout_marginLeft="3dip"
   android:layout_marginRight="3dip"
   android:layout_weight="1"
   android:visibility="gone"
      >
     </LinearLayout>
     <ListView android:id="@+id/oxcache_list"
   android:persistentDrawingCache="animation|scrolling"
   android:cacheColorHint="#00000000"
   android:divider="@color/gray_light"
   android:dividerHeight="1dip"
   android:orientation="vertical"
   android:layout_weight="1"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content">
  </ListView>
.....
     <Button   
         android:id="@+id/list_btn"     
         android:layout_width="wrap_content"    
         android:layout_height="wrap_content"    
         android:layout_marginRight="0dip"
         android:text="@string/list"
         android:textColor="@color/header_text"
         android:background="@drawable/btn_left_unpress"
         style="@style/List"
     />   
     <Button   
         android:id="@+id/map_btn"     
         android:layout_width="wrap_content"    
         android:layout_height="wrap_content"
         android:layout_marginLeft="-8dip"
         android:text="@string/map"
         android:textColor="@color/header_text"
         android:background="@drawable/btn_right_unpress"
         style="@style/List"
     />
在程式中,透過監聽兩個按鈕的click event來切換不同的視窗,重點是什麼情況是右進左出,左進右出了。
listBtn.setOnClickListener(new Button.OnClickListener() {
   @Override
   public void onClick(View v) {
           mOxcacheList.setVisibility(View.VISIBLE);
           mOxcacheList.setClickable(true);
           mOxcacheList.setAnimation(AnimationUtils.loadAnimation(CacheMe.this, R.layout.push_left_in));
           mMapLinear.setVisibility(View.GONE);
           mMapLinear.setAnimation(AnimationUtils.loadAnimation(CacheMe.this, R.layout.push_right_out));
    }
   }
        });
  mapBtn.setOnClickListener(new Button.OnClickListener() {
   @Override
   public void onClick(View v) {
           mMapLinear.setVisibility(View.VISIBLE);
           mMapLinear.setClickable(true);
           mMapLinear.setAnimation(AnimationUtils.loadAnimation(CacheMe.this, R.layout.push_right_in));
           mOxcacheList.setVisibility(View.GONE);
           mOxcacheList.setAnimation(AnimationUtils.loadAnimation(CacheMe.this, R.layout.push_left_out));
    }
   }
        });

2010年12月27日 星期一

如何得知程式是跑在"Debug"模式下

有時候,會需要知道程式現在是跑在debug模式還是release模式下,
像是MapView的Key在Debug和Release的模式下,是需要傳不同的key值才可以的。
下面就是使用方法:

通常如果是debug模式,我們會在AndroidManifest.xml檔案中加入這樣的設定:
...

...

而下面這段程式碼,就可以使用在程式中,來決定目前是不是在debug模式下了。
而我通常會將它寫成static function,方便在各個view中來使用。
public static boolean isDebugMode(Context ctx) {
  PackageInfo packageInfo;
  try {
   packageInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), PackageManager.GET_SIGNATURES);
   int flags = packageInfo.applicationInfo.flags; 
   if ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
       return true;
   }
  } catch (NameNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return false;
 }

2010年11月20日 星期六

將View的內容截取出來

因為程式中會需要截取MapView的內容,並上傳到facebook,所以將截取View內容的方式紀錄下來。

Bitmap bitmap = Bitmap.createBitmap(mapView.getWidth(), mapView.getHeight(), Bitmap.Config.ARGB_8888); 
Canvas canvas = new Canvas(bitmap); 
mapView.draw(canvas);

重點其實只有:
(一)以View的size來建立一個Bitmap。
(二)以這個bitmap來建立canvas。
(三)將mapView的內容畫在canvas上。

然後,就可以將這個Bitmap轉化成PNG的格式,可以儲存下來,或者上傳到網路上,夠簡單了吧。

2010年11月3日 星期三

使用facebook api

在我的程式中有使用facebook api,雖然不是很難,不過也把我使用的方法紀錄和分享下來。

  • login和授權:
facebook api已經將登入和授權整個UI都包好了,使用時也是非常方便。
mFacebook = new Facebook;
...
        if (mFacebook.isSessionValid() == false) {
         mFacebook.authorize(ctx, APP_ID, FB_PERMISSIONS, new DialogListener() {
    @Override
    public void onCancel() {
    }
    @Override
    public void onComplete(Bundle values) {
     post();
    }
    @Override
    public void onError(DialogError e) {
     sendNotify(false);
    }
    @Override
    public void onFacebookError(FacebookError e) {
     sendNotify(false);
    }
         });
        } else {
         post();
        }
當mFacebook.isSessionValid()為true時代表授權還沒有過期,是不需要在要求使用者登錄的,可以繼續我們上傳的程序。

  • Post message:
下面是post message的範例。
  final String GRAPH_PATH = "me/feed";
  final String POST_MESSAGE = "message";
  Bundle params = new Bundle();
  String msgVal = null;
  if (this.msg != null) {
   msgVal = this.title+"\n"+this.msg;
  } else {
   msgVal = this.title;
  }
  params.putString(POST_MESSAGE, msgVal);
  
  try {
   String resp = mFacebook.request(GRAPH_PATH, params, "POST");
   JSONObject json = Util.parseJson(resp);
   postId = json.getString("id");

  • Post photo:
重點在於如何將photo變成binary傳送到facebook;另外縮圖也很重要,facebook上傳照片的時間很長,如果能先縮圖可以減少上傳時間。
  final String GRAPH_PATH = "me/photos";
  final String POST_MESSAGE = "message";
  Bundle params = new Bundle();
  
  String msgVal = null;
  if (this.msg != null) {
   msgVal = this.title+"\n"+this.msg;
  } else {
   msgVal = this.title;
  }
  params.putString(POST_MESSAGE, msgVal);
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  travelMap.compress(Bitmap.CompressFormat.PNG, 100, out);
  params.putByteArray("picture", out.toByteArray());   
        
  try {
   String resp = mFacebook.request(GRAPH_PATH, params, "POST");
   JSONObject json = Util.parseJson(resp);
   postId = json.getString("id");

  • Thread:
因為facebook api會花一些時間等待,所以最好把整個程序放在背景執行會比較好。
    private void post() {
     Thread thread = new Thread()
     {
         @Override
         public void run() {
          boolean bRet = false;
      switch(hi.getType()) {
      case HistoryDB.HISTORY_PHOTO_TYPE:
       bRet = postPhoto();
       break;
           
      case HistoryDB.HISTORY_POI_TYPE:
       bRet = postFeed();
       break;
           
      default:
       break;
      }
          
          Message msg = new Message();
          if (bRet == true)
           msg.arg1 = 1;
          else
           msg.arg1 = 0;
          handler.sendMessage(msg);
         }
     };
     thread.start();
    }
    
    Handler handler=new Handler() {
        @Override
        public void handleMessage(Message msg) {
         if (msg.arg1 == 1) {
          sendNotify(true);
         } else {
          sendNotify(false);
         }
        }
    };