上色

Code Block

2015年12月14日 星期一

[Android] 偵測方向使用不同layout

若要偵測使用者螢幕方向,並使用對應不同xml的layout,可使用下列方式︰

  1. 設計兩種不同layout的xml檔案。
  2. 在AndroidManifest.xml中要改變的activity中新增屬性︰
  3. android:configChanges="orientation|keyboardHidden|screenSize"
  4. 如此一來當方向或螢幕大小改變的時候,就會觸發︰
    onConfigurationChanged(Configuration newConfig)
  5. 依照類似下面的方式判斷長寬,以決定適用的layout file。
    public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            Display display = getWindowManager().getDefaultDisplay();
            int width;
            int height;
            Point size = new Point();
            display.getSize(size);
            width=size.x;
            height=size.y;
            if (width>height) { //Landscape
                setContentView(R.layout.activity_main_land);
                initView();
            }
            else{
                setContentView(R.layout.activity_main_port);
                initView();
            }
        }
    

2015年12月11日 星期五

[Android] Shell Tool for root commands


import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Scanner;

import android.content.res.AssetManager;
import android.os.Build;
import android.util.Log;

public class ShellUtils
{
 private static String busyboxPath="/system/xbin/busybox";

 /**
  * Set custom busybox path
  * @param path Path
  */
 public static void setCustomBusybox(String path){
  busyboxPath = path;
 }
 
 public static boolean checkBusyboxPath(){
  try{
   if (!new File("/system/xbin/busybox").exists()){
    if(!new File("/system/bin/busybox").exists())
     return false;
    else busyboxPath="/system/bin/busybox";
   }
            else busyboxPath="/system/xbin/busybox";
  }catch (SecurityException e){
   return false;
  }
  return true;
 }

 /**
  * Try to get root permission
  * @return true means success; false means fail
  */
 public static boolean rootCheck(){
  //List all the files under "/data/data", doing this operation needs root permission
  //CommandResult commandResult = execCommand(false,true, "ls /data/data/");
  //Empty result means there's no root permission
        //return !commandResult.successMsg.isEmpty();
  return execCommand(false,true,"").result==0;
 }

 @SuppressWarnings("deprecation")
 public static boolean initiateBusybox(){
  //Clear old files
  File busybox = new File(GlobalVariable.getContext().getFilesDir()+"/busybox");
  if (busybox.exists())
   busybox.delete();
  //Copy corresponding busybox to internal folder
  String cpuVersion;
  if (android.os.Build.VERSION.SDK_INT <21)
   cpuVersion= Build.CPU_ABI;
  else
   cpuVersion=Build.SUPPORTED_ABIS[0];
  //Determine busybox version
  String filename;
  cpuVersion=cpuVersion.toLowerCase();
  if (cpuVersion.contains("arm"))
   filename="busybox-armv5l";
  else if (cpuVersion.contains("x86"))
   filename="busybox-i686";
  else
   return false;
  AssetManager assetManager = GlobalVariable.getContext().getAssets();
  InputStream in = null;
  OutputStream out = null;
  try {
   in = assetManager.open(filename);
   out = new FileOutputStream(busybox);
   byte[] buffer = new byte[1024];
   int read;
   while ((read = in.read(buffer)) != -1) {
    out.write(buffer, 0, read);
   }
  }
  catch (IOException e) {
   e.printStackTrace();
   return false;
  }
  finally {
   if (in != null) {
    try {
     in.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if (out != null) {
    try {
     out.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
  //Make busybox executables
  ShellUtils.execCommand(false, true, "chmod 0755 " + GlobalVariable.getContext().getFilesDir() + "/busybox");
  return true;
 }

 /**
  * Execute commands and get the results
  * @param isBusybox Run cmds via busybox or not
     * @param isRoot Run cmds as root?
  * @param cmds Command(s)
  * @return Results of commands
  */
 public static CommandResult execCommand(boolean isBusybox, boolean isRoot, String...cmds){
        int result=-1;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;
        if (cmds==null || cmds.length==0)
            return new CommandResult(result,null,null);
  try{
            Process proc=Runtime.getRuntime().exec(isRoot?"su":"sh");
   DataOutputStream opt = new DataOutputStream(proc.getOutputStream());
   boolean exitCmdFound=false;
   //Write cmds
   for(String cmd:cmds){
                //Using busybox and check its path
    if (isBusybox)
     opt.writeBytes(busyboxPath + " ");
    //Unless make sure cmd is in English, using UTF-8 coding, avoid wrong coding.
    opt.write(cmd.getBytes(Charset.forName("utf-8")));
    if(!exitCmdFound && cmd.equals("exit"))
                    exitCmdFound=true;
    opt.writeBytes("\n");
   }
   if(!exitCmdFound)
                opt.writeBytes("exit\n");
   opt.flush(); 
            //Get results
            result=proc.waitFor();
            successMsg = new StringBuilder();
            errorMsg = new StringBuilder();
            Scanner scanner;
            scanner=new Scanner(new InputStreamReader(proc.getInputStream()));
            while (scanner.hasNextLine())
                successMsg.append(scanner.nextLine());
            scanner=new Scanner(new InputStreamReader(proc.getErrorStream()));
            while (scanner.hasNextLine())
                errorMsg.append(scanner.nextLine());
  } catch (Exception e){
            e.printStackTrace();
        }
        return new CommandResult(result,successMsg==null?null:successMsg.toString(), errorMsg==null?null:errorMsg.toString());
 }

    public static class CommandResult {

        /**
         * Result of command
         * 0: normal
         * else: error
         */
        public int    result;
        public String successMsg;
        public String errorMsg;

        public CommandResult(int result, String successMsg, String errorMsg) {
            this.result = result;
            this.successMsg = successMsg;
            this.errorMsg = errorMsg;
        }
    }
}