廣告

顯示具有 android 標籤的文章。 顯示所有文章
顯示具有 android 標籤的文章。 顯示所有文章

2016年2月25日 星期四

Android Receive SMS Tutorial | android 取得sms內容


testReadSms.java
public class testReadSms extends BodyFragment{

    private SmsBroadcastReceiver receiver = new SmsBroadcastReceiver(new SmsBroadcastReceiver.UpdateSmsEvent() {
        @Override
        public void updateSms(String sms) {
            newMsg.setText(sms);
        }
    });

    private ArrayList smsMessagesList = new ArrayList();
    private ListView smsListView;
    private ArrayAdapter arrayAdapter;
    private TextView newMsg;

    @Override
    public void onStart() {
        super.onStart();

        //regist sms receiver
        Log. e("registerReceiver", "registerReceiver");
        receiver.registerSmsReceiver(activity);
    }

    @Override
    protected View fragmentLayout(LayoutInflater inflater, ViewGroup container) {
        return inflater.inflate(R.layout.test_body_sms, container, false);
    }

    @Override
    protected void setupComponents(View fragmentView) {
        newMsg = (TextView) fragmentView.findViewById(R.id. new_msg);
        smsListView = (ListView) fragmentView.findViewById(R.id. SMSList);
        arrayAdapter = new ArrayAdapter( activity, android.R.layout.simple_list_item_1 , smsMessagesList);
        smsListView.setAdapter(arrayAdapter);
        smsListView.setOnItemClickListener( this);

        refreshSmsInbox();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //activity.unregisterReceiver(receiver);
    }

    public void refreshSmsInbox() {
        ContentResolver contentResolver = activity.getContentResolver();
        Cursor smsInboxCursor = contentResolver.query(Uri.parse("content://sms/inbox"), null, null , null, null);
        int indexBody = smsInboxCursor.getColumnIndex( "body");
        int indexAddress = smsInboxCursor.getColumnIndex( "address");
        if (indexBody < 0 || !smsInboxCursor.moveToFirst()) return;
        arrayAdapter.clear();
        do {
            String str = "SMS From: " + smsInboxCursor.getString(indexAddress) +
                    "\n" + smsInboxCursor.getString(indexBody) + "\n";
            arrayAdapter.add(str);
        } while (smsInboxCursor.moveToNext());
    }

    public void updateList(final String smsMessage) {
        arrayAdapter.insert(smsMessage, 0);
        arrayAdapter.notifyDataSetChanged();
    }

    public void updateNewMsg(final String msg) {
        newMsg.setText(msg);
    }

}


SmsBroadcastReceiver.java
public class SmsBroadcastReceiver extends BroadcastReceiver {

    public static final String SMS_BUNDLE = "pdus";
    public Activity activity;
    public UpdateSmsEvent updateSmsEvent;


    public interface UpdateSmsEvent{
        void updateSms(String sms);
    }

    public SmsBroadcastReceiver(UpdateSmsEvent inte){
        updateSmsEvent = inte;
    }


    public void onReceive(Context context, Intent intent) {
        Bundle intentExtras = intent.getExtras();
        if (intentExtras != null) {
            Object[] sms = (Object[]) intentExtras.get(SMS_BUNDLE);
            String smsMessageStr = "";
            String smsMessageBody= "";
            for (int i = 0; i < sms. length; ++i) {
                SmsMessage smsMessage = SmsMessage. createFromPdu((byte[]) sms[i]);

                String smsBody = smsMessage.getMessageBody().toString();
                String address = smsMessage.getOriginatingAddress();

                //smsMessage.getTimestampMillis() is current time
                smsMessageStr += "SMS From: " + address + "\n" ;
                smsMessageStr += smsBody + "\n" ;
                smsMessageBody = smsMessage.getMessageBody().toString();
            }
            Toast.makeText (context, smsMessageBody, Toast.LENGTH_SHORT).show();
            smsMessageBody = smsMessageBody.replaceAll("\\D+","" );
            //this will update the UI with message
            updateSmsEvent.updateSms(smsMessageBody);
            activity.unregisterReceiver(this);
        }
    }

    public void registerSmsReceiver(Activity activity){
        this.activity = activity;
        IntentFilter filter = new IntentFilter();
        filter.setPriority(999 );
        filter.addAction("android.provider.Telephony.SMS_RECEIVED");
        activity.registerReceiver(this, filter);
    }
}



main ref:

ref:

[android] sms emulator control in Android Studio | android模擬器 模擬簡訊寄送

Tools->Android->Android Device Monitor-> Click on the emulator name in devicess-> Emulator Controls

[android] phone call using intent in android


String phone = location.getPhoneNumber();
//Intent intent = new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phone, null));
//need click call
Intent intent = new Intent(Intent. ACTION_CALL, Uri.fromParts( "tel", phone, null ));
//call directly
activity.startActivity(intent);


add permission in AndroidManifest.xml


[android] Send Email Intent

http://stackoverflow.com/questions/8701634/send-email-intent
Intent emailIntent = new Intent(Intent. ACTION_SENDTO, Uri.fromParts(
        "mailto", "lewisli.acer@gmail.com", null));
emailIntent.putExtra(Intent.EXTRA_EMAIL , "lewisli.acer@gmail.com");
emailIntent.putExtra(Intent.EXTRA_SUBJECT , "Pet");
emailIntent.putExtra(Intent.EXTRA_TEXT , "this is error page");
startActivity(Intent.createChooser(emailIntent, "Report error"));





but can't get result event
http://stackoverflow.com/questions/3778048/how-can-we-use-startactivityforresult-for-email-intent

You can't, this is not part of the API. It returns once you have pressed send button even if it is not sent

2016年1月7日 星期四

[android] 微信接入(登入,發動態) | weChat auth login,share



sample code
https://github.com/cihm/WeChatDemo

註冊
https://open.weixin.qq.com/cgi-bin/userinfo?lang=zh_CN&token=7a348e868afe006e18453eb53e825c65c231e870
教學
http://mobile.51cto.com/others-388965.htm
http://www.eoeandroid.com/thread-547012-1-1.html?_dsign=491583a0
============================
.程式裡的APP key 要使用開發者後台所提供的.
.要使用app_signatures.apk將包名編譯成md5並且填入開發者後台當中.
.或是直接cmd line跑出來,在自己轉小寫
willy key:7ae51e2d4ca6bb6c5df769148071bed6

登入功能需要開通

前提:
 要得到回傳訊息(不管發動態或是登入)
 一定要在自己於微信後台註冊的package(自己的專案)下面
 新增一個package 叫"wxapi"
 然後在此package下面新增
 "WXEntryActivity.java"並實作IWXAPIEventHandler則就可在onResp拿到回傳

 注意:
 package名稱(wxapi )跟java檔名稱(WXEntryActivity )一要要這樣叫

 androidmenifest:

    
        
        
        
    


===========
分享動態功能
WXEntryActivity => SendToWXActivity
 發送文字
 .將app註冊到APP
 .自訂TextView(EditText )
 .自訂dialog(MMAlert)
 .初始化一个 WXTextObject 对象(將要分享的文字放進去)
 .初始化WXMediaMessage(WXTextObject放進去 )
 .构造一个 Req(SendMessageToWX.Req)
 .调用api接口发送数据到微信(api .sendReq(req) )
 .WXEntryActivity 的onResp會顯示成功與否
其他發送訊息如程式sample所演示.

圖文同時的話目前找到用WXWebpageObject代替


package com.example.wechatsdk.party3control;

import android.app.Activity;
import android.app.Dialog;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;


import com.tencent.mm.sdk.openapi.BaseReq;
import com.tencent.mm.sdk.openapi.BaseResp;
import com.tencent.mm.sdk.openapi.ConstantsAPI;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.SendAuth;
import com.tencent.mm.sdk.openapi.SendMessageToWX;
import com.tencent.mm.sdk.openapi.ShowMessageFromWX;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.mm.sdk.openapi.WXAppExtendObject;
import com.tencent.mm.sdk.openapi.WXMediaMessage;
import com.tencent.mm.sdk.openapi.WXWebpageObject;

/**
* Created by 1409035  lewisli on 2015/11/17.
*/
public class WeChatControl {

    private static WeChatControl instance = new WeChatControl();

    private WeChatControl() {

    }

    public static WeChatControl getInstance() {
        return instance ;
    }

    private static final int THUMB_SIZE = 150 ;
    private IWXAPI iwaxaApi;
    private ApplicationInfo applicationInfo;
    private String appKey;
    private String TAG = "com.wechat.api.wechat_API_KEY";



    public void shareMessage(Activity activity, String text, Bitmap bitmap) {
        //ref:http://mobile.9sssd.com/android/art/1059
        // custom dialog


        String url = "http://test";// 收到分享的好友点击信息会跳转到这个地址去
        WXWebpageObject localWXWebpageObject = new WXWebpageObject();
        localWXWebpageObject.webpageUrl = url;

        WXMediaMessage msg = new WXMediaMessage(localWXWebpageObject);

        //msg.setThumbImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
        //Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.send_img);

        Bitmap thumbBmp = Bitmap. createScaledBitmap(bitmap, THUMB_SIZE, THUMB_SIZE, true );

        msg.thumbData = Util.bmpToByteArrayFix(thumbBmp, true);  // 设置缩略图
        bitmap.recycle();

        msg.title = text;
        msg.description = text;

        SendMessageToWX.Req req = new SendMessageToWX.Req();
        req.transaction = System.currentTimeMillis() + "";
        req.message = msg;

        //send global or friend only
        //req.scene = isTimelineCb.isChecked() ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
        req. scene = SendMessageToWX.Req.WXSceneTimeline;
        getiIWXAPI(activity).sendReq(req);

        //finish();
    }


    public IWXAPI getiIWXAPI(Activity activity) {
        if (iwaxaApi == null) {
            setiIWXAPI(WXAPIFactory.createWXAPI (activity, getAppKey(activity), true));


            Log.e( "!!!!", "getiIWXAPI" );
            iwaxaApi.registerApp(getAppKey(activity));
            //iwaxaApi.handleIntent(activity.getIntent(), this);

        }
        return iwaxaApi ;
    }

    public void setiIWXAPI(IWXAPI iwaxAPI) {
        this.iwaxaApi = iwaxAPI;
    }


    private ApplicationInfo getApplicationInfo(Activity activity) {
        if (applicationInfo == null) {
            try {
                setApplicationInfo(activity.getPackageManager().getApplicationInfo(activity.getPackageName(), PackageManager.GET_META_DATA));
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        return applicationInfo ;
    }

    private void setApplicationInfo(ApplicationInfo applicationInfo) {
        this.applicationInfo = applicationInfo;
    }

    public String getAppKey(Activity activity) {
        if (appKey == null) {
            setAppKey(getApplicationInfo(activity).metaData.getString( TAG));
        }
        return appKey ;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }


    public void login(Activity activity){
        final SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "wechat2chongba";
        getiIWXAPI(activity).sendReq(req);
    }



}
=============
登入功能:

文件
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=88a73255c4a18aa152113ef684fce5dfd2347719&lang=zh_CN

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317853&lang=zh_CN

  在onResp回傳 =>BaseResp resp
  做轉型
  SendAuth.Resp sendResp = (SendAuth.Resp) resp;
  取token
  sendResp.token
 // 官方文件寫錯(他寫code),但實際上是 token



STEP1:user token to get access_token and openid

https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxbff6de7ebe6c9498&secret=a50b0b62ae77557b289c487308aa9faa&code=0112342663e805e50dd7fbe001075d0L&grant_type=authorization_code


STEP2: use refresh_token
=>第一次可跳過,又或者你只需要取得一次用戶資訊,那也可跳過此步驟

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=wxbff6de7ebe6c9498&grant_type=refresh_token&refresh_token=OezXcEiiBSKSxW0eoylIeILPYvLIWkzXq-H0gG9o7k8Dt9ilr91flHHcPwl78kdLCCcgvEVqvNaksf3wpgyqlaIvgSqQwbgV9LnBvgafjJpdJa7R-XExsaMWDy_o7LpKMPkIGvnQsHpKY2_LP5z12g


STEP3: use access_token and openid get user info
https://api.weixin.qq.com/sns/userinfo?access_token=OezXcEiiBSKSxW0eoylIeILPYvLIWkzXq-H0gG9o7k8Dt9ilr91flHHcPwl78kdLXZNZvaTI5NyTOMl1klSSoTbRuXuzd52ZqVe5X9O6QGvd7wFUYOVubwRWhDGLcHzbKzPoZ_ukdukfBBgW1sL7tQ, unionid=oS9mHwNTZYvYeerdgwiGaEzqMBHc&openid=oibTCuAkkFgeUkJeV8bdp6wSgYJI




WXEntryActivity  code


package com.acer.wxapi;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.util.task.json.JsonGetTask;


import com.acer.R;
import com.acer.pet.util.ViewUtils;
import com.example.wechatsdk.party3control.WeChatControl;
import com.tencent.mm.sdk.openapi.BaseReq;
import com.tencent.mm.sdk.openapi.BaseResp;
import com.tencent.mm.sdk.openapi.ConstantsAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.SendAuth;

import java.util.ArrayList;
import java.util.HashMap;

import static android.util.Constants.NETWORK_ERROR;
import static com.acer.pet.util.ViewUtils.loadingFinish;
import static com.acer.pet.util.ViewUtils.loadingStart;


public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

    private static final int TIMELINE_SUPPORTED_VERSION = 0x21020001 ;
    private static final int RETURN_MSG_TYPE_LOGIN = 1 ;
    private static final int RETURN_MSG_TYPE_SHARE = 2 ;
    private String appId;
    private String secret;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        WeChatControl.getInstance().getiIWXAPI( this).handleIntent(getIntent(), this);


    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.e( "onNewIntent", "!!!" + intent);
        setIntent(intent);
        WeChatControl.getInstance().getiIWXAPI( this).handleIntent(getIntent(), this);
    }

    // 微信发送请求到第三方应用时,会回调到该方法
    @Override
    public void onReq(BaseReq req) {
        Log.e( "onReq", "!!!" + req);
        switch (req.getType()) {
            case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
                //goToGetMsg();
                break;
            case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
                //goToShowMsg((ShowMessageFromWX.Req) req);
                break;
            default:
                break;
        }
    }

    // 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
    @Override
    public void onResp(BaseResp resp) {
        int result = 0;
        Log.e( "onResp", "!!!" + resp.getType());
        switch (resp.errCode) {
            case BaseResp.ErrCode.ERR_OK:

                switch (resp.getType()) {
                    case RETURN_MSG_TYPE_LOGIN:

                        SendAuth.Resp sendResp = (SendAuth.Resp) resp;
                        Log. e("resp.errCode", "!!!" + sendResp.errCode);
                        Log. e("resp.state", "!!!" + sendResp.state);
                        Log. e("resp.token", "!!!" + sendResp.token);

                        //loadingStart(this);
                        secret = getResources().getString(R.string.com_wechat_api_wechat_API_SECRET );
                        appId = WeChatControl.getInstance().getAppKey( this);
                        getAccessToken(sendResp. token);

                        //官方文件寫錯,是token,不是 code
                        // 拿到了微信返回的 code,立马再去请求access_token
                        //String code = ((SendAuth.Resp) resp).code;

                        // 就在这个地方,用网络库什么的或者自己封的网络 api,发请求去咯,注意是 get请求

                        break;

                    case RETURN_MSG_TYPE_SHARE:
                        //"微信分享成功";
                        finish();
                        break;
                }

                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                result = com.example.wechatsdk.party3control.R.string.errcode_cancel;
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                result = com.example.wechatsdk.party3control.R.string.errcode_deny;
                break;
            default:
                result = com.example.wechatsdk.party3control.R.string.errcode_unknown;
                break;
        }

    }

    //stpe1
    public void getAccessToken(String toekn) {

        String apiUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + secret + "&code=" + toekn + "&grant_type=authorization_code" ;

        (new JsonGetTask(apiUrl) {
            @Override
            protected void onPostExecute(ArrayList> arrayList) {
                if ((arrayList.size() == 1 && null != arrayList.get(0).get(NETWORK_ERROR ))) {

                    Log.e("getAccessToken", "NETWORK_ERROR");

                } else {

                    //我要做的事情
                    Log.e( "getAccessToken", arrayList.toString());

                    if (!arrayList.get( 0).containsKey( "errcode")) {

                        String refreshToken = (String) arrayList.get(0).get("refresh_token" );
                        String accessToken = (String) arrayList.get(0).get("access_token" );
                        String openid = (String) arrayList.get( 0).get( "openid");
                        getUserInfo(refreshToken, accessToken, openid);

                    } else {
                        Log. e("error", arrayList.toString());
                    }

                }

                //loadingFinish();

            }
        }).execute();
    }


    //stpe2
    public void getUserInfo(String refreshToken, String accessToken, String openid) {

        String apiUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid;

        (new JsonGetTask(apiUrl) {
            @Override
            protected void onPostExecute(ArrayList> arrayList) {
                if ((arrayList.size() == 1 && null != arrayList.get(0).get(NETWORK_ERROR ))) {
                    Log.e("getUserInfo", "NETWORK_ERROR");
                } else {

                    Log.e("getAccessToken", arrayList.toString());

                    if (!arrayList.get( 0).containsKey( "errcode")) {

                        String nickname = (String) arrayList.get(0).get("nickname" );
                        String unionid = (String) arrayList.get( 0).get( "unionid");
                        String headimgurl = (String) arrayList.get(0).get("headimgurl" );

                        Log.e("userinfo", "nickname:"+nickname+"===unionid:"+unionid+"===headimgurl"+headimgurl);

                    } else {
                        Log. e("error", arrayList.toString());
                    }


                }

                //loadingFinish();
                finish();
            }
        }).execute();
    }


}


[android] 解決list item事件,與該list item裡面的"元件" 造成的事件衝突


1.將事件寫在BaseAdapter的 getView裡面
ref:https://tausiq.wordpress.com/2012/08/22/android-listview-example-with-custom-adapter/
    public View getView(int index, View view, final ViewGroup parent) {
     
     view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              //do things here
            }
        });
     
     button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              //do things here
            }
        });
  }

2.設定list item裡面的"元件"
ref:http://stackoverflow.com/questions/6703390/listview-setonitemclicklistener-not-working-by-adding-button

Try seting your buttons(or any other views you want to handle click inside a list item) like this:

android:focusable="false"
android:focusableInTouchMode="false"


2015年11月19日 星期四

[android] Use "meta-data" from AndroidManifest.xml

想說第三方的app key參數都放在<meta-data >裡
但如果value直過大時(46464646464123),
ex:
<meta-data
    android :name="API_KEY"
    android :value="46464646464123 " />
此時直接從程式裡引用此值會出錯.

解法:
<meta-data android:name="zoo" android:value="@string/kangaroo" />

benefits:

2014年11月30日 星期日

[Android 顯示從網路下載的圖片][Android show picture from url]

常常會用到即時從網路下載圖片,並顯示於原件上。
下載圖片的方式有很多種,這邊用AsyncTask 搭配 http GET的方式顯示
圖片在imageView上,(可以自行將imageView 改成其他元件,grid, list等等)。










































範例:


import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

public class Lewis extends Activity {
 private ImageView imageView;
 private ProgressDialog simpleWaitDialog;
 private final static String url = "http://i.imgur.com/pJv6ccq.jpg";

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  imageView = (ImageView) findViewById(R.id.imageView);
  new DownloadImage().execute(url); 
 }

 private class DownloadImage extends AsyncTask {
  @Override
  protected Bitmap doInBackground(String... param) {
   return downloadBitmap(param[0]);
  }

  @Override
  protected void onPreExecute() {
   simpleWaitDialog = ProgressDialog.show(
     Lewis.this, "Wait",
     "Downloading Image");
  }

  protected void onPostExecute(Bitmap result) {
   imageView.setImageBitmap(result);
   simpleWaitDialog.dismiss();

  }

  private Bitmap downloadBitmap(String url) {
   final DefaultHttpClient client = new DefaultHttpClient();
   final HttpGet getRequest = new HttpGet(url);
   try {
    HttpResponse response = client.execute(getRequest);
    final int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode != HttpStatus.SC_OK) {
     return null;
    }
    final HttpEntity entity = response.getEntity();
    if (entity != null) {
     InputStream inputStream = null;
     try {
      inputStream = entity.getContent();
      final Bitmap bitmap = BitmapFactory
        .decodeStream(inputStream);
      
      return bitmap;
      
     } finally {
      if (inputStream != null) {
       inputStream.close();
      }
      entity.consumeContent();
     }
    }
   } catch (Exception e) {

    getRequest.abort();
   }
   return null;
  }
 }
}

2014年11月29日 星期六

[Android_ColorPicker_Dialog][Android_調色盤_用dialog方式]






















將以下程式加入貼到專案中。

import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

public class ColorPickerDialog extends Dialog {
 private final boolean debug = true;
 private final String TAG = "ColorPicker";
 
 Context context;
 private String title;
 private int mInitialColor;
    private OnColorChangedListener mListener;

 
    public ColorPickerDialog(Context context, String title, 
      OnColorChangedListener listener) {
     this(context, Color.BLACK, title, listener);
    }
    
  
    public ColorPickerDialog(Context context, int initialColor, 
      String title, OnColorChangedListener listener) {
        super(context);
        this.context = context;
        mListener = listener;
        mInitialColor = initialColor;
        this.title = title;
        
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WindowManager manager = getWindow().getWindowManager();
  int height = (int) (manager.getDefaultDisplay().getHeight() * 0.5f);
  int width = (int) (manager.getDefaultDisplay().getWidth() * 0.7f);
  ColorPickerView myView = new ColorPickerView(context, height, width);
        setContentView(myView);
        setTitle(title);
    }
    
    private class ColorPickerView extends View {
     private Paint mPaint;
     private Paint mCenterPaint;
     private Paint mLinePaint;
     private Paint mRectPaint;
     
     private Shader rectShader;
     private float rectLeft;
     private float rectTop;
     private float rectRight;
     private float rectBottom;
        
     private final int[] mCircleColors;
     private final int[] mRectColors;
     
     private int mHeight;
     private int mWidth;
     private float r;
     private float centerRadius;
     
     private boolean downInCircle = true;
     private boolean downInRect;
     private boolean highlightCenter;
     private boolean highlightCenterLittle;
     
  public ColorPickerView(Context context, int height, int width) {
   super(context);
   this.mHeight = height - 36;
   this.mWidth = width;
   setMinimumHeight(height - 36);
   setMinimumWidth(width);
   
   
      mCircleColors = new int[] {0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 
        0xFF00FFFF, 0xFF00FF00,0xFFFFFF00, 0xFFFF0000};
      Shader s = new SweepGradient(0, 0, mCircleColors, null);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setShader(s);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(50);
            r = width / 2 * 0.7f - mPaint.getStrokeWidth() * 0.5f;
            
           
            mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mCenterPaint.setColor(mInitialColor);
            mCenterPaint.setStrokeWidth(5);
            centerRadius = (r - mPaint.getStrokeWidth() / 2 ) * 0.7f;
            
            
            mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mLinePaint.setColor(Color.parseColor("#72A1D1"));
            mLinePaint.setStrokeWidth(4);
            
        
            mRectColors = new int[]{0xFF000000, mCenterPaint.getColor(), 0xFFFFFFFF};
            mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mRectPaint.setStrokeWidth(5);
            rectLeft = -r - mPaint.getStrokeWidth() * 0.5f;
            rectTop = r + mPaint.getStrokeWidth() * 0.5f + 
              mLinePaint.getStrokeMiter() * 0.5f + 15;
            rectRight = r + mPaint.getStrokeWidth() * 0.5f;
            rectBottom = rectTop + 50;
  }

  @Override
  protected void onDraw(Canvas canvas) {
            canvas.translate(mWidth / 2, mHeight / 2 - 50);
            canvas.drawCircle(0, 0, centerRadius,  mCenterPaint);
            if (highlightCenter || highlightCenterLittle) {
                int c = mCenterPaint.getColor();
                mCenterPaint.setStyle(Paint.Style.STROKE);
                if(highlightCenter) {
                 mCenterPaint.setAlpha(0xFF);
                }else if(highlightCenterLittle) {
                 mCenterPaint.setAlpha(0x90);
                }
                canvas.drawCircle(0, 0, 
                  centerRadius + mCenterPaint.getStrokeWidth(),  mCenterPaint);
                
                mCenterPaint.setStyle(Paint.Style.FILL);
                mCenterPaint.setColor(c);
            }
            canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
            if(downInCircle) {
             mRectColors[1] = mCenterPaint.getColor();
            }
            rectShader = new LinearGradient(rectLeft, 0, rectRight, 0, mRectColors, null, Shader.TileMode.MIRROR);
            mRectPaint.setShader(rectShader);
            canvas.drawRect(rectLeft, rectTop, rectRight, rectBottom, mRectPaint);
            float offset = mLinePaint.getStrokeWidth() / 2;
            canvas.drawLine(rectLeft - offset, rectTop - offset * 2, 
              rectLeft - offset, rectBottom + offset * 2, mLinePaint);
            canvas.drawLine(rectLeft - offset * 2, rectTop - offset, 
              rectRight + offset * 2, rectTop - offset, mLinePaint);
            canvas.drawLine(rectRight + offset, rectTop - offset * 2, 
              rectRight + offset, rectBottom + offset * 2, mLinePaint);
            canvas.drawLine(rectLeft - offset * 2, rectBottom + offset, 
              rectRight + offset * 2, rectBottom + offset, mLinePaint);
   super.onDraw(canvas);
  }
  
  @Override
  public boolean onTouchEvent(MotionEvent event) {
   float x = event.getX() - mWidth / 2;
            float y = event.getY() - mHeight / 2 + 50;
            boolean inCircle = inColorCircle(x, y, 
              r + mPaint.getStrokeWidth() / 2, r - mPaint.getStrokeWidth() / 2);
            boolean inCenter = inCenter(x, y, centerRadius);
            boolean inRect = inRect(x, y);
            
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                 downInCircle = inCircle;
                 downInRect = inRect;
                 highlightCenter = inCenter;
                case MotionEvent.ACTION_MOVE:
                 if(downInCircle && inCircle) {
                  float angle = (float) Math.atan2(y, x);
                        float unit = (float) (angle / (2 * Math.PI));
                        if (unit < 0) {
                            unit += 1;
                        }
                  mCenterPaint.setColor(interpCircleColor(mCircleColors, unit));
                  if(debug) Log.v(TAG, ": " + x + "," + y);
                 }else if(downInRect && inRect) {
                  mCenterPaint.setColor(interpRectColor(mRectColors, x));
                 }
                 if(debug) Log.v(TAG, "[MOVE] : " + highlightCenter + ": " + highlightCenterLittle + " : " + inCenter);
                 if((highlightCenter && inCenter) || (highlightCenterLittle && inCenter)) {
                  highlightCenter = true;
                  highlightCenterLittle = false;
                 } else if(highlightCenter || highlightCenterLittle) {
                  highlightCenter = false;
                  highlightCenterLittle = true;
                 } else {
                  highlightCenter = false;
                  highlightCenterLittle = false;
                 }
                    invalidate();
                 break;
                case MotionEvent.ACTION_UP:
                 if(highlightCenter && inCenter) {
                  if(mListener != null) {
                   mListener.colorChanged(mCenterPaint.getColor());
                      ColorPickerDialog.this.dismiss();
                  }
                 }
                 if(downInCircle) {
                  downInCircle = false;
                 }
                 if(downInRect) {
                  downInRect = false;
                 }
                 if(highlightCenter) {
                  highlightCenter = false;
                 }
                 if(highlightCenterLittle) {
                  highlightCenterLittle = false;
                 }
                 invalidate();
                    break;
            }
            return true;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(mWidth, mHeight);
  }

 
  private boolean inColorCircle(float x, float y, float outRadius, float inRadius) {
   double outCircle = Math.PI * outRadius * outRadius;
   double inCircle = Math.PI * inRadius * inRadius;
   double fingerCircle = Math.PI * (x * x + y * y);
   if(fingerCircle < outCircle && fingerCircle > inCircle) {
    return true;
   }else {
    return false;
   }
  }
  
 
  private boolean inCenter(float x, float y, float centerRadius) {
   double centerCircle = Math.PI * centerRadius * centerRadius;
   double fingerCircle = Math.PI * (x * x + y * y);
   if(fingerCircle < centerCircle) {
    return true;
   }else {
    return false;
   }
  }
  
 
  private boolean inRect(float x, float y) {
   if( x <= rectRight && x >=rectLeft && y <= rectBottom && y >=rectTop) {
    return true;
   } else {
    return false;
   }
  }
  
  
  private int interpCircleColor(int colors[], float unit) {
            if (unit <= 0) {
                return colors[0];
            }
            if (unit >= 1) {
                return colors[colors.length - 1];
            }
            
            float p = unit * (colors.length - 1);
            int i = (int)p;
            p -= i;

            // now p is just the fractional part [0...1) and i is the index
            int c0 = colors[i];
            int c1 = colors[i+1];
            int a = ave(Color.alpha(c0), Color.alpha(c1), p);
            int r = ave(Color.red(c0), Color.red(c1), p);
            int g = ave(Color.green(c0), Color.green(c1), p);
            int b = ave(Color.blue(c0), Color.blue(c1), p);
          //  Log.e("colort2222", Integer.toString(Color.argb(a, r, g, b)));
            return Color.argb(a, r, g, b);
        }
  
  
  private int interpRectColor(int colors[], float x) {
   int a, r, g, b, c0, c1;
         float p;
         if (x < 0) {
          c0 = colors[0]; 
          c1 = colors[1];
          p = (x + rectRight) / rectRight;
         } else {
          c0 = colors[1];
          c1 = colors[2];
          p = x / rectRight;
         }
         a = ave(Color.alpha(c0), Color.alpha(c1), p);
         r = ave(Color.red(c0), Color.red(c1), p);
         g = ave(Color.green(c0), Color.green(c1), p);
         b = ave(Color.blue(c0), Color.blue(c1), p);
         return Color.argb(a, r, g, b);
  }
  
  private int ave(int s, int d, float p) {
            return s + Math.round(p * (d - s));
        }
    }
    
    
    public interface OnColorChangedListener {
     
        void colorChanged(int color);
    }
    
    public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }

 public int getmInitialColor() {
  return mInitialColor;
 }

 public void setmInitialColor(int mInitialColor) {
  this.mInitialColor = mInitialColor;
 }

 public OnColorChangedListener getmListener() {
  return mListener;
 }

 public void setmListener(OnColorChangedListener mListener) {
  this.mListener = mListener;
 }
}




用法:在你要改顏色地方加入以下程式碼。
AlertDialog.Builder editDialog = new AlertDialog.Builder(DragListActivity.this);
editDialog.setTitle("pick color");

 dialog = new ColorPickerDialog(mContext, tempColor, "11",
 new ColorPickerDialog.OnColorChangedListener() {
   public void colorChanged(int color2) 
   {
    //set your color variable
   }
 });
 dialog.show();



[Android Animation _use extends Animation_3DFlip ][Android 讓layout有動畫_用extends Animation的方式_3D翻頁效果 ]

這篇用extends Animation 來做特效。

先將以下程式加入專案。


public class Flip3dAnimation extends Animation {
 private final float mFromDegrees;
 private final float mToDegrees;
 private final float mCenterX;
 private final float mCenterY;
 private Camera mCamera;

 public Flip3dAnimation(float fromDegrees, float toDegrees, float centerX,
   float centerY) {
  mFromDegrees = fromDegrees;
  mToDegrees = toDegrees;
  mCenterX = centerX;
  mCenterY = centerY;
 }

 @Override
 public void initialize(int width, int height, int parentWidth,
   int parentHeight) {
  super.initialize(width, height, parentWidth, parentHeight);
  mCamera = new Camera();
 }

 @Override
 protected void applyTransformation(float interpolatedTime, Transformation t) {
  final float fromDegrees = mFromDegrees;
  float degrees = fromDegrees
    + ((mToDegrees - fromDegrees) * interpolatedTime);

  final float centerX = mCenterX;
  final float centerY = mCenterY;
  final Camera camera = mCamera;

  final Matrix matrix = t.getMatrix();

  camera.save();

  camera.rotateY(degrees);

  camera.getMatrix(matrix);
  camera.restore();

  matrix.preTranslate(-centerX, -centerY);
  matrix.postTranslate(centerX, centerY);

 }

}



使用方法:

如果你是要點擊按鈕或item以後轉跳畫面,想要等動畫跑完再轉跳畫面,可以用以下方法,
600代表0.6秒後再轉跳畫面


final float centerX = view.getWidth() / 2.0f;
final float centerY = view.getHeight() / 2.0f;
final Flip3dAnimation rotation =  new Flip3dAnimation(0, 90, centerX, centerY);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
              
view.startAnimation(rotation);
               
view.postDelayed(new Runnable() {
                   
          public void run() {                
            //do things here            
          }
},600);

[Android Animation _use xml][Android 讓layout有動畫_用xml的方式 ]

將動畫的xml檔寫如下的資料夾中























範例:
這邊用兩段式動畫當例子。

animSlide_up = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_up); 
layout_login.setAnimation(animSlide_up);
layout_login.setVisibility(View.GONE); 

animSlide_down = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down); 
layout_after_login.setAnimation(animSlide_down);
layout_after_login.setVisibility(View.VISIBLE);



fade_in.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true" >
    <alpha
        android:duration="1000"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />
</set>

fade_out.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true" >
    <alpha
        android:duration="1000"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.0" />
</set>
blink.xml
<?xml version="1.0" encoding="utf-8"?>
    <alpha android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:duration="600"
        android:repeatMode="reverse"
        android:repeatCount="infinite"/>
</set>
zoom_in.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true" >
    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="3"
        android:toYScale="3" >
    </scale>
</set>
zoom_out.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true" >
    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.5"
        android:toYScale="0.5" >
    </scale>
</set>
rotate.xml
<?xml version="1.0" encoding="utf-8"?>
    <rotate android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="600"
        android:repeatMode="restart"
        android:repeatCount="infinite"
        android:interpolator="@android:anim/cycle_interpolator"/>
</set>
move.xml
<?xml version="1.0" encoding="utf-8"?>
<set
    android:interpolator="@android:anim/linear_interpolator"
    android:fillAfter="true">
   <translate
        android:fromXDelta="0%p"
        android:toXDelta="75%p"
        android:duration="800" />
</set>
slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true" >
    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:toXScale="1.0"
        android:toYScale="0.0" />
</set>
slide_down.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true">
    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="0.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>
bounce.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true"
    android:interpolator="@android:anim/bounce_interpolator">
    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="0.0"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>
sequential.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator" >
    <!-- Use startOffset to give delay between animations -->
    <!-- Move -->
    <translate
        android:duration="800"
        android:fillAfter="true"
        android:fromXDelta="0%p"
        android:startOffset="300"
        android:toXDelta="75%p" />
    <translate
        android:duration="800"
        android:fillAfter="true"
        android:fromYDelta="0%p"
        android:startOffset="1100"
        android:toYDelta="70%p" />
    <translate
        android:duration="800"
        android:fillAfter="true"
        android:fromXDelta="0%p"
        android:startOffset="1900"
        android:toXDelta="-75%p" />
    <translate
        android:duration="800"
        android:fillAfter="true"
        android:fromYDelta="0%p"
        android:startOffset="2700"
        android:toYDelta="-70%p" />
    <!-- Rotate 360 degrees -->
    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/cycle_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="3800"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:toDegrees="360" />
</set>
together.xml
<?xml version="1.0" encoding="utf-8"?>
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator" >
    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="4000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="4"
        android:toYScale="4" >
    </scale>
    <!-- Rotate 180 degrees -->
    <rotate
        android:duration="500"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:toDegrees="360" />
</set>


裡面的參數請自行微調。

最後副上一個也還不錯的animation lib

https://github.com/dkmeteor/ActivityAnimationLib

最近又有更新:http://developer.android.com/training/animation/cardflip.html