2014年6月25日 星期三

Android Button UI 按鈕 美化

改變基本灰色樣式按鈕

1.首先要在drawable-hdpi建立一個xml檔
 選擇Android XML File->Next
選擇Drawable->命名->選擇selector
 btn_black.xml加入程式碼
這裡舉一個黑色的按鈕,其他顏色請參考來源網站

    
        
         
            
            
            
        
    
    
        
            
            
            
            
        
    

2.在你的strings.xml裡加入

3.activity_main.xml
"@drawable/btn_black"->btn_black.xml名稱
"@style/ButtonText"->strings.xml裡style name="ButtonText"名稱
參考來源: http://androidtutorials4beginners.blogspot.tw/2013/04/android-colored-gradient-buttons-using.html

2014年6月24日 星期二

Android google map addMarker setOnMarkerClickListener 標記後動作

使用google map標記功能addMarker後,需要增加動作可以使用OnMarkerClickListener和OnMarkerDragListene
例如:點取標記後,跳去其他頁面。
前置作業:有使用google map,有使用addMarker
1.MainActivity.java
public class MainActivity extends FragmentActivity implements OnMarkerClickListener{ //需引用OnMarkerClickListener
 private GoogleMap map;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 map = ((SupportMapFragment) getSupportFragmentManager()
    .findFragmentById(R.id.map)).getMap();
  
  LatLng p1 = new LatLng(22.6297370, 120.3278820);
  if (map != null) {
   map.setOnMarkerClickListener(this); //點取Marker動作
   // google mark
   map.addMarker(new MarkerOptions()
     .position(p1)
     .title("多那之高雄中正門市")
     .snippet("咖啡.烘培"));
  }

 }

 /* 點選marker顯示 */
 @Override
   public boolean onMarkerClick(Marker marker) {
  /* 此處增加點取後想要的動作*/
  Toast.makeText(getApplicationContext(),"Marker Clicked: " + marker.getTitle(), Toast.LENGTH_LONG).show(); //顯示點取addMarker的標題
     return false;
   }

}

2014年6月19日 星期四

Android QRcode

掃描QRcode 讓資訊顯示出來
需要安裝QRDroid
1.activity_main.xml

            
2.MainActivity.java
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  info = (TextView) findViewById(R.id.info);
  scanner = (Button) findViewById(R.id.scanner);
  scanner.setOnClickListener(new Button.OnClickListener() {
   @Override
   public void onClick(View v) {

    // TODO Auto-generated method stub
    Intent iScaner = new Intent("la.droid.qr.scan"); // 使用QRDroid的掃描功能
    iScaner.putExtra("la.droid.qr.complete", true); // 完整回傳,不截掉scheme
    try {
     // 開啟 QRDroid App 的掃描功能,等待 call back onActivityResult()
     startActivityForResult(iScaner, 0);
    } catch (ActivityNotFoundException ex) {
     // 若沒安裝 QRDroid,則開啟 Google Play商店,並顯示 QRDroid App
     Intent intent = new Intent(Intent.ACTION_VIEW, Uri
       .parse("market://details?id=la.droid.qr"));
     startActivity(intent);
    }
   }
  });
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) { //不需要建立onActivityResult
  super.onActivityResult(requestCode, resultCode, data);

  if (0 == requestCode && null != data && data.getExtras() != null) {
   // 掃描結果存放在 key 為 la.droid.qr.result 的值中
   String result = data.getExtras().getString("la.droid.qr.result");

   info.setText(result); // 將結果顯示在 TextVeiw 中
  }
 }
3.建立QRcode的網站 http://www.quickmark.com.tw/Cht/qrcode-datamatrix-generator/default.asp?qrText
4.掃描圖片




參考來源:
http://elviselle.blogspot.tw/2013/06/android-app-qr-code.html

2014年6月16日 星期一

Android shortcut 桌面 捷徑

自動建立桌面捷徑的方法,使用shortcut
首先要宣告
1.AndroidManifest.xml

2.MainActivity.java
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  addShortcut();
 }
/* 建立桌面捷徑 */
 private void addShortcut() {
  Intent shortcutIntent = new Intent(getApplicationContext(),
    MainActivity.class); // 啟動捷徑入口,一般用MainActivity,有使用其他入口則填入相對名稱,ex:有使用SplashScreen
  shortcutIntent.setAction(Intent.ACTION_MAIN);
  Intent addIntent = new Intent();
  addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); // shortcutIntent送入
  addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
    getString(R.string.app_name)); // 捷徑app名稱
  addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
    Intent.ShortcutIconResource.fromContext(
      getApplicationContext(),// 捷徑app圖
      R.drawable.ic_launcher));
  addIntent.putExtra("duplicate", false); // 只創建一次
  addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); // 安裝
  getApplicationContext().sendBroadcast(addIntent); // 送出廣播
 }
參考來源:
http://stackoverflow.com/questions/22829647/programmatically-add-the-widget-to-home-screen-in-android
http://stackoverflow.com/questions/21542409/home-screen-app-shortcut-is-not-working-android-app-isnt-installed

2014年6月12日 星期四

Android Apk Download Install Update 下載安裝 更新 APP

大陸更新app方法從網路上找到這篇http://mft.iteye.com/blog/1686524
基本上就是把apk檔跟一個文件檔(版本資訊)放在雲端上面,但就卡在版本資訊,上面連結沒有寫這部分,於是我找到了要用json,這裡卡超久,最後找到此連結http://blog.it4fun.net/archives/112 
,接著出現問題2,android改版後網路要求變嚴格,會出現android.os.NetworkOnMainThreadException問題,解決此參考http://goo.gl/yFbGdR
,接著還有問題3 ,java.lang.string cannot be converted to jsonarray,解決方法http://goo.gl/Qv0mym
就是不能用POST,要用GET。

1.MainActivity.java
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends Activity {
 /* update */
 protected static final int UPDATA_CLIENT = 0;
 protected static final int CHECK_UPDATE = 1;
 protected static final int DOWN_ERROR = 0;
 /** Called when the activity is first created. */
 private int serverVersion = 1; // 現在版本
 private int newServerVersion; // 最新版本
 private String downLoadApkUrl = "https://dl.dropbox.com/s/vahfdayyluk151z/Android.apk"; // 放置最新檔案網址

 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  /* update */
  /* 加入StrictMode避免發生 android.os.NetworkOnMainThreadException */
  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
    .detectDiskReads().detectDiskWrites().detectNetwork()
    .penaltyLog().build());
  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
    .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
    .penaltyLog().penaltyDeath().build());

  JSONArray obj = getJson("http://terryyamg.github.io/myweb/update_verson.json"); // 更新版本文件檔位置
  Log.i("obj:", obj + "");
  try {
   for (int i = 0; i < obj.length(); i++) {
    JSONObject data = obj.getJSONObject(i);
    newServerVersion = Integer.parseInt(data.getString("code")); // code為名稱,抓出來newServerVersion為值
   }
  } catch (JSONException e) {

  } catch (NullPointerException e) {
   Log.i("data", "NullPointException");
  }

  new Thread(new Runnable() {
   public void run() {
    try {
     Message msg = new Message();
     msg.what = CHECK_UPDATE;
     handler.sendMessage(msg);

    } catch (NumberFormatException e) {
     // TODO Auto-generated catch block

    } catch (Exception e) {
     // TODO Auto-generated catch block

    }

   }
  }).start();
 }

 /* update */
 public static JSONArray getJson(String url) {
  InputStream is = null;
  String result = "";
  // 若線上資料為陣列,則使用JSONArray
  JSONArray jsonArray = null;
  // 若線上資料為單筆資料,則使用JSONObject
  // JSONObject jsonObj = null;
  // 透過HTTP連線取得回應
  try {
   HttpClient httpclient = new DefaultHttpClient(); // for port 80
   HttpGet httppost = new HttpGet(url); // 要用Get,用Post會出現
             // java.lang.string cannot
             // be converted to jsonarray
   HttpResponse response = httpclient.execute(httppost);
   Log.i("response:", response + ""); // 沒有值會catch錯誤,加入前面StrictMode就可以
   HttpEntity entity = response.getEntity();
   Log.i("entity:", entity + "");
   is = entity.getContent();
   Log.i("is:", is + "");
  } catch (Exception e) {
   e.printStackTrace();
  }
  // 讀取回應
  try {
   BufferedReader reader = new BufferedReader(new InputStreamReader(
     is, "utf8"), 9999999); // 99999為傳流大小,若資料很大,可自行調整
   StringBuilder sb = new StringBuilder();
   String line = null;
   while ((line = reader.readLine()) != null) {
    // 逐行取得資料
    sb.append(line + "\n");
   }
   is.close();
   result = sb.toString();
   Log.i("result:", result + ""); // LogCat會印出json ex:[{"code":"1"}]
  } catch (Exception e) {
   e.printStackTrace();
  }
  // 轉換文字為JSONArray
  try {
   jsonArray = new JSONArray(result);
  } catch (JSONException e) {
   e.printStackTrace();
  }
  return jsonArray;
 }

 public void showUpdateDialog() {

  @SuppressWarnings("unused")
  AlertDialog alert = new AlertDialog.Builder(MainActivity.this)
    .setTitle("更新提示").setIcon(android.R.drawable.ic_dialog_info)
    .setMessage("最新優惠出來啦,快來下載更新")
    .setPositiveButton("下載", new DialogInterface.OnClickListener() {

     public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss(); // 關閉對話框
      downLoadApk();
     }

    }).show();

 }

 protected void downLoadApk() {
  final ProgressDialog pd; // 進度條對話框
  pd = new ProgressDialog(this);
  pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  pd.setMessage("正在下載更新");
  pd.show();
  new Thread() {
   @Override
   public void run() {
    try {
     File file = getFileFromServer(downLoadApkUrl, pd);
     sleep(3000);
     installApk(file);
     pd.dismiss(); // 結束進度條對話框
    } catch (Exception e) {
     pd.dismiss();
     Message msg = new Message();
     msg.what = DOWN_ERROR;
     handler.sendMessage(msg);
     e.printStackTrace();
    }
   }
  }.start();
 }

 public static File getFileFromServer(String path, ProgressDialog pd)
   throws Exception {
  /* 如果相等的話表示當前的SDcard掛載在手機上並且是可用的 */
  if (Environment.getExternalStorageState().equals(
    Environment.MEDIA_MOUNTED)) {
   URL url = new URL(path);
   HttpURLConnection conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(5000);
   pd.setMax(conn.getContentLength()); // 獲取副本文件大小
   InputStream is = conn.getInputStream();
   File file = new File(Environment.getExternalStorageDirectory(),
     "update.apk");
   FileOutputStream fos = new FileOutputStream(file);
   BufferedInputStream bis = new BufferedInputStream(is);
   byte[] buffer = new byte[1024];
   int len;
   int total = 0;
   while ((len = bis.read(buffer)) != -1) {
    fos.write(buffer, 0, len);
    total += len;
    pd.setProgress(total); // 獲取當前下載量
   }
   fos.close();
   bis.close();
   is.close();
   return file;
  } else {
   return null;
  }
 }

 /* 安裝APK */
 protected void installApk(File file) {
  Intent intent = new Intent();
  intent.setAction(Intent.ACTION_VIEW); // 執行動作
  intent.setDataAndType(Uri.fromFile(file),
    "application/vnd.android.package-archive"); // 執行的數據類型
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //2015.05.28 update 安裝完成後啟動app
  startActivity(intent);
 }

 Handler handler = new Handler() {

  @Override
  public void handleMessage(Message msg) {
   // TODO Auto-generated method stub
   super.handleMessage(msg);
   switch (msg.what) {
   case DOWN_ERROR:
    // 下載APK失敗
    Toast.makeText(getApplicationContext(), "下載新版本失敗", 1).show();
    break;
   case CHECK_UPDATE:
    // 檢查更新

    if (serverVersion == 0) {
     serverVersion = newServerVersion;
    }

    if (serverVersion != newServerVersion) {
     Log.i("serverVersion:", serverVersion + ""); // 顯示現在版本
     Log.i("newServerVersion:", newServerVersion + ""); // 顯示最新版本
     showUpdateDialog(); // 執行更新
    }
    break;
   }
  }
 };
}
2.AndroidManifest.xml
加入使用網路權限

3.update_verson.json
[{"code":"1"}]

2014年6月9日 星期一

Android apk 檔案上傳 Dropbox

有鑑於執行時還沒要開始上傳至Google商店,可以藉由Dropbox來放置APK檔測試
1.開啟Dropbox資料夾->在APK檔案上按右鍵->分享Dropbox連結
2.此時會複製連結,將其貼在網址 ex:https://www.dropbox.com/s/xxxxxxxxx/Android.apk
3.將www改成dl ex:https://dl.dropbox.com/s/xxxxxxxxx/Android.apk
4.輸入此網址即可自動立即下載apk檔案,不須手動點選下載。

Android GPS 定位 距離 偵測

開車照相偵測app都會偵測某個點有照相偵測機,然後發出警告,此app會用到GPS與Broadcast功能。需建立GPSService.java與GPSReceiver.java檔(與MainActivity.java同資料夾)
1.activity_main.xml
輸入接近目標的經緯度,打勾啟動

  
   
  
  
  
  

2.AndroidManifest.xml
加入GPSReceiver接收功能與GPSService廣播功能,VIBRATE手機震動功能,ACCESS_FINE_LOCATION定位功能。



        
            
                
            
        

        
3.MainActivity.java
 private EditText lat, lon;
 private CheckBox checkBox_service;
 private TextView output;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  lat = (EditText) findViewById(R.id.txtLat);
  lon = (EditText) findViewById(R.id.txtLong);
  checkBox_service = (CheckBox) findViewById(R.id.checkBox_service);
  output = (TextView) findViewById(R.id.output);
  if (checkBox_service.isChecked()) {
   start_Click(); //啟動功能
  } else {
   stop_Click(); //停止功能
  }
 }
 public void start_Click() {
  float latitude = Float.parseFloat(lat.getText().toString()); //取得輸入座標
  float longitude = Float.parseFloat(lon.getText().toString()); //取得輸入座標
  Intent intent = new Intent(this, GPSService.class); //送至GPSService.java
  intent.putExtra("LATITUDE", latitude); //發送座標至GPSService
  intent.putExtra("LONGITUDE", longitude); //發送座標至GPSService
  startService(intent);
  output.setText("服務啟動中");
 }

 public void stop_Click() {
  Intent intent = new Intent(this, GPSService.class);
  stopService(intent);
  output.setText("服務停止中");
 }
4.GPSService.java
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

public class GPSService extends Service implements LocationListener {
 private LocationManager manager;
 private boolean isInArea;
 private double latitude, longitude;

 @Override
 public void onCreate() {

  manager = (LocationManager) getSystemService(LOCATION_SERVICE);
  manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 1,
    this);
  manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 1,
    this);
  isInArea = false; //是否在範圍內
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  try {
   latitude = (double) intent.getFloatExtra("LATITUDE1", 22.6297370f); //取得座標
   longitude = (double) intent.getFloatExtra("LONGITUDE1", 120.3278820f); //取得座標
  } catch (NullPointerException e) {
   Log.i("GPSService","NullPointException");
  }
  Log.d("GPSService", "lat/long: " + latitude + ": " + longitude);
  return START_STICKY;
 }

 @Override
 public void onDestroy() {
  manager.removeUpdates(this); //移除定位服務更新
 }

 @Override
 public void onLocationChanged(Location current) {
  // TODO Auto-generated method stub
  if (current == null)
   return;
  Location dest = new Location(current); //取得現在位置
  dest.setLatitude(latitude); //取得現在位置座標
  dest.setLongitude(longitude); //取得現在位置座標
  float distance = current.distanceTo(dest); //計算目標位置與現在位置距離
  if (distance < 1000.0) { //當目標小於1公里時
   if (isInArea == false) { //在區域內
    Intent intent = new Intent("android.broadcast.LOCATION"); //啟動廣播服務
    sendBroadcast(intent); //發送廣播
    isInArea = true; //是否在區域內:true
   }
  } else {
   isInArea = false; //是否在區域內:false
  }

 }

 @Override
 public void onStatusChanged(String provider, int status, Bundle extras) {
  // TODO Auto-generated method stub

 }

 @Override
 public void onProviderEnabled(String provider) {
  // TODO Auto-generated method stub

 }

 @Override
 public void onProviderDisabled(String provider) {
  // TODO Auto-generated method stub

 }

 @Override
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return null;
 }

}

5.GPSReceiver.java
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Vibrator;

public class GPSReceiver extends BroadcastReceiver {
 static int id = 70000;
 @SuppressWarnings("deprecation")
 @Override
 public void onReceive(Context context, Intent intent) {
  //Notification
  NotificationManager notificationManager = (NotificationManager) context
    .getSystemService(android.content.Context.NOTIFICATION_SERVICE);

  Notification notification = new Notification(R.drawable.ic_launcher,
    "您已經接近目標", System.currentTimeMillis()); //跳出Notification訊息
  Intent newintent = new Intent(context, MainActivity.class);
  PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
    newintent, 0);
  notification.setLatestEventInfo(context, "再接近就要被拍了!!", null, contentIntent);

  notificationManager.notify(id++, notification);
  
  //手機震動
  Vibrator vibrator = (Vibrator) context
    .getSystemService(Context.VIBRATOR_SERVICE);
  vibrator.vibrate(500); // 半秒
 }
}

參考來源:
http://goo.gl/BbbtPe
http://hscc.cs.nctu.edu.tw/~lincyu/Android/Chapter7.pdf