1. 程式人生 > >Android USB Host的使用詳解

Android USB Host的使用詳解

【廢話一段】

      這段時間,我的小組正在開發一個Android主機的系統,這個系統需要外接USB的指紋機、讀卡器、U盤,硬體已經有了,主機是一個開發板介面豐富,並且支援Android USB Host模式,外設自然不用說。

     但是碰到了一個問題,驅動!本來這個專案是源於Windows的,外設全部是針對Windows而開發的,如果要用專門的驅動,那麼開發Android本身就需要複雜的過程。後來經過硬體工程師的改造,我們將USB換成了HID模式,減輕開發難度。

     經過一段時間搜尋網上資料,關於Android USB Host的資料可以說非常少,不是少數,而是幾乎雷同。我是百度+google,更換無數中英文關鍵字,最後我如願完成自己的專案,和HID裝置正常通訊了,並且識別了U盤。對於網路上中文資料的少而單一的現狀,我決定自己寫一篇文章,讓同行們少走彎路。

    我的程式碼參考了來自“開源中國”部分資料,如果有解決不了的,可以在那裡查詢。

【基礎功能】

    注意:本文的步驟,可能需要你具備Root的許可權,否則有些操作可能會無法完成。強烈建議你先root裝置。

    步驟一:你必須確定你的Android裝置支援USB Host,具體如何確定啊,還是看裝置的說明書吧。如果支援,進入下一步驟。

    步驟二:確定Android有沒有開啟USB Host的許可權,必須是開啟的才能通訊。首先用RE檔案管理器(或者連線Eclipse時使用DDMS檢視),反正要能進入以下目錄:/system/etc/permissions。

你應該要能看到目錄有一個“android.hardware.usb.host.xml”,一個“handheld_core_hardware.xml(手機)”或者“tablet_core_hardware.xml(平板)”,

       如果看不到“android.hardware.usb.host.xml”,那麼就用記事本寫入以下程式碼,儲存,然後PUSH或貼上到/system/etc/permissions目錄下。

<span style="font-family: 'Comic Sans MS';"><permissions>
      <feature name="android.hardware.usb.host"/> 
</permissions></span>

  步驟三:拷出“handheld_core_hardware.xml(手機)”或者“tablet_core_hardware.xml(平板)”檔案,怎麼操作?我是用Eclipse的DDMS中的File Explorer把檔案pull出來的,還可以用其他方法。

         開啟檔案,你應該可以看到<permissions>結點下面有不少東西,檢查有沒有一段:

<span style="font-family: 'Comic Sans MS';"><feature name="android.hardware.usb.host" /></span>

         確定沒有就補上去,比如我的是:

<span style="font-family: 'Comic Sans MS';"><permissions>
    <feature name="android.hardware.camera" />
    <feature name="android.hardware.location" />
    <feature name="android.hardware.location.network" />
    <feature name="android.hardware.sensor.compass" />
    <feature name="android.hardware.sensor.accelerometer" />
    <feature name="android.hardware.bluetooth" />
    <feature name="android.hardware.touchscreen" />
    <feature name="android.hardware.microphone" />
    <feature name="android.hardware.screen.portrait" />
    <feature name="android.hardware.screen.landscape" />
    <!-- 下面這個許可權是我新增的 -->
    <feature name="android.hardware.usb.host" />
</permissions></span>

     步驟四:以上步驟做完後,請重啟你的裝置。

【程式碼內容】

          步驟一: 這裡有個細節,就是【AndroidManifest.xml】檔案中的許可權,網上的多數文章,包括google的官方文件都只講到其一,其實還有一個,留意程式碼。

     先貼上【AndroidManifest.xml】

<span style="font-family: 'Comic Sans MS';"><manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.<a target=_blank target="_blank" name="baidusnap0" style="color: rgb(202, 0, 0);"></a>usbmanager"
    android:versionCode="1"
    android:versionName="1.0" >
   <!-- 這個許可權是必須有的,否則操作不了硬體,google的文件沒有說出來,據說是因為有過濾器後自動獲得,但是我的專案沒這句話不成功。 -->
    <uses-permission android:name="android.permission.HARDWARE_TEST" />
  <!-- 這句話也是必須的 -->
    <uses-feature android:name="android.hardware.usb.host" android:required="true"/>
    <!-- SDK必須是12以上的,因為從 Android3.1開始,才正式支援USB Host -->
    <uses-sdk
        android:minSdkVersion="12"
        android:targetSdkVersion="17" />
                                          
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                                                          
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <!-- 以下這個過濾器是要手工增加上,如果不增加也可以在程式碼中動態註冊,不過我的程式碼是在這裡註冊 -->
            <intent-filter>
                <action
                    android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
             <!-- 以下這個meta-data是要手工增加上,他是用來過濾你的具體USB裝置的,其中的device_filter是個xml檔案 -->
            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"   
                android:resource="@xml/device_filter"/>
                                            
        </activity>
    </application>
                                          
</manifest></span>

    步驟二:有沒有發現,我們還需要一個device_filte.xml檔案,這個檔案包含有你的USB裝置的ProductID和VendorID,即我們常說的PID和VID,不知道這2個值的,請查Windows的裝置管理器屬性。記住:Windows用的是16進製表示的,你必須將它轉為10進位制,以下有說明。

       新增步驟:在Eclipse專案中找到res結點,看有沒有xml資料夾,如果沒有就點右鍵--new---folder,新增資料夾名xml,然後在該xml資料夾下用同樣的方法新增一個device_filte.xml檔案,檔名一定不能錯,內容如下:

<span style="font-family: 'Comic Sans MS';"><?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 億捷U盤,vid的16進位制是090C,pid是1000,轉10進位制是分別是2316,4096 -->
    <usb-device vendor-id="2316" product-id="4096"/>
    <!-- M1讀卡器 ,vid的16進位制是0483,pid是5750,轉10進位制是分別是1155,22352-->
    <usb-device vendor-id="1155" product-id="22352"/>
</resources></span>

        怎麼轉16進製為10進位制???用windows計算器啊,1.檢視型別是科學型,2.選中16進位制,3.輸入值,4.再選擇回10進位制就可以了。

步驟三:佈局檔案其實應該是因人而異的,由於我剛做的時候是隨意列出的,不建議大家仿照。我的檔名是activity_main.xml,你們的可能是main.xml,不一定要一模一樣,只要啊Activity程式碼描述清楚就行。我的程式碼基本沒用到多少控制元件,請適當過濾。

<span style="font-family: 'Comic Sans MS';"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
                          
    <TextView
        android:id="@+id/tvtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="usb簡易除錯工具" />
                          
    <EditText
        android:id="@+id/etxsend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/tvtitle"
        android:layout_below="@+id/tvtitle"
        android:ems="10"
        android:hint="傳送內容"
        android:visibility="invisible" />
                          
    <EditText
        android:id="@+id/etxreceive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btsend"
        android:layout_below="@+id/btsend"
        android:layout_marginTop="37dp"
        android:ems="10"
        android:hint="接收內容"
        android:visibility="invisible" />
                          
    <Button
        android:id="@+id/btreceive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etxreceive"
        android:layout_below="@+id/etxreceive"
        android:text="接收" />
                          
    <Button
        android:id="@+id/btsend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etxsend"
        android:layout_below="@+id/etxsend"
        android:layout_marginTop="16dp"
        android:text="傳送" />
                          
    <ListView
        android:id="@+id/lsv1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btreceive"
        android:layout_below="@+id/btreceive" >
    </ListView>
                          
</RelativeLayout></span>

步驟四:好吧,我承認我比較囉嗦,到現在才進入步驟四的MainActivity.java,由於我的目標更多是讓大家知道如何連線上裝置,因此程式碼顯得隨意,並且這些程式碼在網上也能搜尋到,因此寫的不是很好,但是做了非常多註釋,值得參考。

<span style="font-family: 'Comic Sans MS';">package com.example.usbmanager;
         
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
         
import android.os.Bundle;
import android.R.string;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.DataSetObserver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
         
public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";   //記錄標識
    private Button btsend;      //傳送按鈕
    private UsbManager manager;   //USB管理器
    private UsbDevice mUsbDevice;  //找到的USB裝置
    private ListView lsv1;         //顯示USB資訊的
    private UsbInterface mInterface;   
    private UsbDeviceConnection mDeviceConnection;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btsend = (Button) findViewById(R.id.btsend);
         
        btsend.setOnClickListener(btsendListener);
         
        lsv1 = (ListView) findViewById(R.id.lsv1);
        // 獲取USB裝置
        manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        if (manager == null) {
            return;
        } else {
            Log.i(TAG, "usb裝置:" + String.valueOf(manager.toString()));
        }
        HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
        Log.i(TAG, "usb裝置:" + String.valueOf(deviceList.size()));
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        ArrayList<String> USBDeviceList = new ArrayList<String>(); // 存放USB裝置的數量
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
         
            USBDeviceList.add(String.valueOf(device.getVendorId()));
            USBDeviceList.add(String.valueOf(device.getProductId()));
         
            // 在這裡新增處理裝置的程式碼
            if (device.getVendorId() == 1155 && device.getProductId() == 22352) {
                mUsbDevice = device;
                Log.i(TAG, "找到裝置");
            }
        }
        // 建立一個ArrayAdapter
        lsv1.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, USBDeviceList));
        findIntfAndEpt();
                 
    }
         
    private byte[] Sendbytes;    //傳送資訊位元組
    private byte[] Receiveytes;  //接收資訊位元組
    private OnClickListener btsendListener = new OnClickListener() {
        int ret = -100;
        @Override
        public void onClick(View v) {
            /*
             * 請注意,本模組通訊的內容使用的協議是HID讀卡器協議,不會和大家手上的裝置一樣
             * 請大家在測試時參考自己手上的裝置資料,嚴格按照HID標準執行傳送和接收資料
             * 我的範例使用的裝置是廣州微雲電子的WY-M1RW-01非接觸式讀卡器,outputreport是64,因此我傳送的位元組長度是64
             * 我傳送的位元組內容是要求讀卡器蜂鳴器響兩短一長
             */
            String testString = "90000CB20301F401F401F401F407D447FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
            Sendbytes = clsPublic.HexString2Bytes(testString);
                     
            // 1,傳送準備命令
            ret = mDeviceConnection.bulkTransfer(epOut, Sendbytes, Sendbytes.length, 5000); 
            Log.i(TAG,"已經發送!");
                     
            // 2,接收發送成功資訊
            Receiveytes=new byte[64];     //這裡的64是裝置定義的,不是我隨便亂寫,大家要根據裝置而定
            ret = mDeviceConnection.bulkTransfer(epIn, Receiveytes, Receiveytes.length, 10000);
            Log.i(TAG,"接收返回值:" + String.valueOf(ret));
            if(ret != 64) {
                DisplayToast("接收返回值"+String.valueOf(ret));
                return;
            }
            else {
                //檢視返回值
                DisplayToast(clsPublic.Bytes2HexString(Receiveytes));
                Log.i(TAG,clsPublic.Bytes2HexString(Receiveytes));
            }
        }
    };
         
    // 顯示提示的函式,這樣可以省事,哈哈
    public void DisplayToast(CharSequence str) {
        Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG);
        // 設定Toast顯示的位置
        toast.setGravity(Gravity.TOP, 0, 200);
        // 顯示Toast
        toast.show();
    }
             
    // 尋找介面和分配結點
    private void findIntfAndEpt() {
        if (mUsbDevice == null) {
            Log.i(TAG,"沒有找到裝置");
            return;
        }
        for (int i = 0; i < mUsbDevice.getInterfaceCount();) {
            // 獲取裝置介面,一般都是一個介面,你可以列印getInterfaceCount()方法檢視接
            // 口的個數,在這個介面上有兩個端點,OUT 和 IN 
            UsbInterface intf = mUsbDevice.getInterface(i);
            Log.d(TAG, i + " " + intf);
            mInterface = intf;
            break;
        }
         
        if (mInterface != null) {
            UsbDeviceConnection connection = null;
            // 判斷是否有許可權
            if(manager.hasPermission(mUsbDevice)) {
                // 開啟裝置,獲取 UsbDeviceConnection 物件,連線裝置,用於後面的通訊
                connection = manager.openDevice(mUsbDevice); 
                if (connection == null) {
                    return;
                }
                if (connection.claimInterface(mInterface, true)) {
                    Log.i(TAG,"找到介面");
                    mDeviceConnection = connection;
                    //用UsbDeviceConnection 與 UsbInterface 進行端點設定和通訊
                    getEndpoint(mDeviceConnection,mInterface);
                } else {
                    connection.close();
                }
            } else {
                Log.i(TAG,"沒有許可權");
            }
        }
        else {
            Log.i(TAG,"沒有找到介面");
        }
    }
             
             
    private UsbEndpoint epOut;
    private UsbEndpoint epIn;
    //用UsbDeviceConnection 與 UsbInterface 進行端點設定和通訊
    private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf) {
        if (intf.getEndpoint(1) != null) {
            epOut = intf.getEndpoint(1);
        }
        if (intf.getEndpoint(0) != null) {
            epIn = intf.getEndpoint(0);
        }
    }
             
             
}</span>

步驟五:我在步驟四的程式碼中包含有個類clsPublic,這個類是用來轉換十六進位制和字串的,一般來說大家也不需要,但是考慮程式碼完整性,我也貼上來。這個類和MainActivity是在同一個包名下的檔案clsPublic.java。

<span style="font-family: 'Comic Sans MS';">package com.example.usbmanager;
       
public class clsPublic {
    // 整數到位元組陣列轉換
     public static byte[] int2bytes(int n) {
     byte[] ab = new byte[4];
     ab[0] = (byte) (0xff & n);
     ab[1] = (byte) ((0xff00 & n) >> 8);
     ab[2] = (byte) ((0xff0000 & n) >> 16);
     ab[3] = (byte) ((0xff000000 & n) >> 24);
     return ab;
     }
       
     // 位元組陣列到整數的轉換
     public static int bytes2int(byte b[]) {
     int s = 0;
     s = ((((b[0] & 0xff) << 8 | (b[1] & 0xff)) << 8) | (b[2] & 0xff)) << 8
     | (b[3] & 0xff);
     return s;
     }
       
     // 位元組轉換到字元
     public static char byte2char(byte b) {
     return (char) b;
     }
       
     private final static byte[] hex = "0123456789ABCDEF".getBytes();
       
     private static int parse(char c) {
     if (c >= 'a')
     return (c - 'a' + 10) & 0x0f;
     if (c >= 'A')
     return (c - 'A' + 10) & 0x0f;
     return (c - '0') & 0x0f;
     }
       
     // 從位元組陣列到十六進位制字串轉換
     public static String Bytes2HexString(byte[] b) {
     byte[] buff = new byte[2 * b.length];
     for (int i = 0; i < b.length; i++) {
     buff[2 * i] = hex[(b[i] >> 4) & 0x0f];
     buff[2 * i + 1] = hex[b[i] & 0x0f];
     }
     return new String(buff);
     }
       
     // 從十六進位制字串到位元組陣列轉換
     public static byte[] HexString2Bytes(String hexstr) {
     byte[] b = new byte[hexstr.length() / 2];
     int j = 0;
     for (int i = 0; i < b.length; i++) {
     char c0 = hexstr.charAt(j++);
     char c1 = hexstr.charAt(j++);
     b[i] = (byte) ((parse(c0) << 4) | parse(c1));
     }
     return b;
     }
}</span>

步驟六:

          製作完成軟體後,安裝到裝置上,或者直接用Eclipse除錯執行。然後插入USB-HID裝置,幸運的話,你會看到系統彈出一個開啟方式的提示(我的裝置是這樣的,其他裝置不知道是什麼結果)。

相關推薦

Android USB Host的使用

【廢話一段】       這段時間,我的小組正在開發一個Android主機的系統,這個系統需要外接USB的指紋機、讀卡器、U盤,硬體已經有了,主機是一個開發板介面豐富,並且支援Android USB Host模式,外設自然不用說。      但是碰到了一個問題,驅動!本來這個專案是源於Windows的

Android USB Host 使用(U盤)(一)

首先說一下為什麼要寫關於Android USB Host通訊的介紹,對於Android程式原來說不懂硬體做USB通訊確實開頭比較難,但是Google API介紹還是很詳細的,而且網上也有很多例子,不過網上的基本把介紹和例子分開,光介紹不給例子,給個例子又不知道它是幹什麼的或

aNDROID之MEDIapLaYER

iap music media 詳解 list oid aid 5% layer %E8%BD%AC%E8%BD%BD%E4%B8%80%E4%B8%AA%E5%9B%BE%E7%89%87%E5%A4%84%E7%90%86%E5%B7%A5%E5%85%B7%E7%B1

Android RxJava操作符系列: 變換操作符

urn 原因 轉換 需要 生產 依賴 reat 入門 所有 Rxjava,由於其基於事件流的鏈式調用、邏輯簡潔 & 使用簡單的特點,深受各大 Android開發者的歡迎。Github截圖 如果還不了解 RxJava,請看文章:Android:這是一篇 清晰 &

android:exported 屬性

itl fas 默認 之前 綁定 四大 nbsp ring ins http://blog.csdn.net/watermusicyes/article/details/46460347 昨天在用360掃描應用漏洞時,掃描結果,出來一個android:exported屬性,

Android SDK Manager

eba 調試 測試工具 使用說明 服務 能力 bar 部分 以及 Android基礎知識——Android SDK Manager詳解 做Android開發時,免不了使用Android SDK Manager,安裝需要的sdk版本、buildTool

IOS和Android系統區別

清理 span back 一個 style 沙盒 安裝 最大值 完全 IOS系統(非開源,不可擴展) iphone沙盒機制解釋:應用程序位於文件系統的嚴格限制部分,程序不能直接訪問其他應用程序。 1、iOS的編程語言Objective-C 2、IOS采用的是沙盒運行

Android Volley框架

注:文章出自http://blog.csdn.net/guolin_blog/article/details/17482095,有興趣可以先去閱讀。 Volley簡介 對於Android系統網路通訊,我們知道目前用的最普遍的就是HttpClient和HttpURLConnection,但是H

Android快取機制之硬碟快取DiskLruCache

簡介 防止多圖OOM的核心解決思路就是使用LruCache技術。但LruCache只是管理了記憶體中圖片的儲存與釋放,如果圖片從記憶體中被移除的話,那麼又需要從網路上重新載入一次圖片,這顯然非常耗時。對此,Google又提供了一套硬碟快取的解決方案:DiskLruCache(非Google官方編

Android pm 命令

一、pm命令介紹與包名資訊查詢 1.pm命令介紹 pm工具為包管理(package manager)的簡稱 可以使用pm工具來執行應用的安裝和查詢應用的資訊、系統許可權、控制應用 pm工具是Android開發與測試過程中必不可少的工具,shell命令格式如下: pm <

Android開發:Handler的記憶體洩露

原文:https://blog.csdn.net/carson_ho/article/details/52693211 前言 記憶體洩露在Android開發中非常常見 記憶體洩露的定義:本該被回收的物件不能被回收而停留在堆記憶體中

Android 四大元件中 android:exported 屬性

當我們在用360等檢測軟體掃描應用漏洞時,掃描結果可能歸類為安全漏洞,涉及一個Android:exported屬性,這個屬性究竟是用來幹嘛的呢,詳情見下圖: 因此,查了官方API,學習了一下這個屬性! android:exported 是Android中的四大元件 Ac

Android permission許可權

        許可權是一種安全機制。Android許可權主要用於限制應用程式內部某些具有限制性特性的功能使用以及應用程式之間的元件訪問。在Android開發中,基本上都會遇到聯網的需求,我們知道都需要加上聯網所需要的許可權: <uses-perm

Android Paging library(二)

重要API及原始碼分析 文章目錄 1.重要API介紹 1.1 DataSource 1.2 PageList 1.3 PagedListAdapter 2.原始碼解析 1.重要API介紹 Pagin

Android Paging library(一)

官方文件翻譯 文章目錄 1.概覽 1.1 庫架構 1.2 支援不同的資料架構 1.2.1 網路獲取或者資料庫 1.2.2 網路和資料庫同時獲取 1.2.3 處理網路錯誤 1.2.4 更新

Android USB Host開發之manager.getDeviceList()獲取不到裝置列表【轉載】

原文:https://www.2cto.com/kf/201305/211304.html 同樣遇到這樣的問題,我的Android裝置是原道N12C,官方的4.0.3系統,遇到這個問題,後來找了半天找到的,現在彙總一下吧: 1、建立 android.hardware.usb.h

Linux USB驅動

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android WebView使用包括js互調(by 星空武哥)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android Canvas繪圖

  Android中使用圖形處理引擎,2D部分是android SDK內部自己提供,3D部分是用Open GL ES 1.0。今天我們主要要了解的是2D相關的,如果你想看3D的話那麼可以跳過這篇文章。 大部分2D使用的api都在android.graphics和android.graphics.

Android 視窗Flags

轉自:https://www.jianshu.com/p/567ff949219a Android 視窗Flags詳解 這裡主要探討Touchable,Focusable,OutsideTouchable,TouchModal這四個混合使用的效果。 public static final