2015年6月24日 星期三

談願景和企業文化 (Vision and Culture)

從出社會工作到現在已經十多載,經歷了幾家公司,也看盡公司的起起落落。有些公司 business model 一直抓不到,一直在找尋機會如何 break even。有些公司曾經非常的成功,但大環境的變遷導致市場巨變,原本的勝利方程式變成了毒藥。或者是公司的產品沒跟上市場脈動,與消費者漸行漸遠。

這篇先不談複雜的問題,例如領導階層的問題,創新能力,市場分析等等...
我只想從這幾年的心得來談談兩個主題:
  • Vision 願景
  • Culture 企業文化
Vision 願景

Vision 的中文是願景,我覺得願景又分趨勢願景和積極願景

趨勢願景就像是你預期 10 年後將會是什麼樣的世界?根據這樣的變化你可以做甚麼樣的事情或產品來迎接未來的市場

積極願景是你希望10 年打造出什麼樣的世界讓未來更美好?這個層次是比趨勢願景更高一等級,他代表的是創造!

為什麼要有 Vision?先回想一下你看戰爭片或警匪片的時候,狙擊手通常是在什麼樣的位子?當然是在制高點把目標物看的一清二楚,才能夠在扣下扳機之後一槍命中。當一個領導就像狙擊手一樣,必須站在制高點才能看的遠,去看十年之後的方向在哪,到達終點的路途有哪些障礙物。如果站的不夠高就無法看的遠,只能夠一路跌跌撞撞的摸索,或者看著其他成功者所開闢出來的道路尾隨。

因為站的夠高看的夠遠,才能知道前方的路要怎麼走,有哪些障礙物,才能依據所看到的情報規劃出 roadmap。例如你在亞馬遜森林中迷路了,想要找到一條出路,首先你必須先找到一個高台或爬上一顆高大的樹,看一下四周環境,例如太陽的方位,附近是否有河流或村莊,亞馬遜河在哪裡,

要如何規劃思考願景?其實是一個大哉問。以近代企業來說,似乎只有賈伯斯是個能看穿未來世界,一手規劃從 iPod 到 iPhone /iPad,建立行動市場的生態 (App Store)。但是,難道必須如強者賈伯斯之超人才能去做願景規劃嗎?其實非也!任何企業都需要願景,也必須投入資源去探索願景,雖然我輩之流不能像賈伯斯一樣登高一呼叫大家 Follow ME!但透過持續的探索和持續的修正,也能為企業找出一條血路出來,就算不是康莊大道,也能是個到達目的地的崎嶇小徑。

我想強調一個重點,沒有多少強者能夠一開始就能準確預測未來的三五年的市場趨勢,因為現在已經是全球化的世界,任何國家或市場的脈動都可能會影響未來的發展。唯有透過不斷的探索,才能找到那條崎嶇小徑,如果只是佇在那裏不動等人家搶灘頭堡後再去 Follow,那只是不斷地採別人的足跡撿拾剩餘的價值;又或者是亂槍打鳥毫無章法的淺嚐即止,不願意認真的深入研究嘗試,員工只會被你搞得頭昏腦脹、筋疲力盡。


Culture 企業文化

剛畢業投入社會的時候,對於企業文化這個名詞完全沒有概念,當時很流行 HP Way 這樣概念的東西,只覺得好像是一家大公司的 slogan,用來提升自己形象的廣告詞。隨著工作打滾多年之後,漸漸的對企業文化這個 term 有了比較深入的了解,原來他可以不是 Slogan,他應該是企業組織裡的 DNA,去驅動每一個單位裡每一位員工。

其實每一個公司都有他的企業文化,差別只是在於和他的 Slogan是否相符而已,台灣一些公司還是和以前反共復國時期一樣,以為只要把標語寫在牆上事情就會成真。DNA是騙不了人的,就好像是偷生的小孩用DNA就能驗出真假一樣,把自己公司說的天花亂墜,但DNA是騙不了人的。企業文化通常是由創辦人在建立公司的過程當中,內斂萃取出來的特質所形成的。

企業文化之重要在於他決定了企業做事情的態度,例如:Amazon 上自創辦人兼 CEO Jeff Bezos,下到 Engineer / service staffs,所奉行的企業文化就是 "Customer Centric",所以 Jeff可以為了一個客訴而親自對客戶溝通。一家企業能不能夠屹立不搖,就在於他能不能夠有效的建立企業文化,去驅動自己、去改革自己。企業文化不需要是艱深的道理,重要的是他是不是深植在企業組織的 DNA 裡,而不只是那牆上的標語而已。



自己從工作到現在總共待過大約三家公司,有幾家是大企業,有一家是startup的小公司,好像都經歷了由盛到衰的歷程(是自己帶衰嗎?),回想過去這些企業的歷史,似乎都和願景及企業文化有蠻大關聯。隨著全球化浪潮,科技業也正面臨新的工業化時代,許多產業正處於破壞式創新。要如何在新的工業化革命中不被消滅,我認為積極的探索願景和良好的企業文化,絕對是這場革命浪潮中迫切需要的救生圈。


Android BLE App Development


Bluetooth and BLE

BLE standards for Bluetooth Low Energy, which is standardized as Bluetooth 4.0. It doesn't intended to replace or enhance classic Bluetooth (2.0/3.0). It is designed with a new protocol stack for the specific services/applications which required much lower power consumption for getting much longer lifetime. 



BLE defines following roles in GAP from the perspective of BLE .
- Peripheral device
The peripheral device broadcast
- Central device

I think you can find a lot of more information in the other public websites. Therefore the detail about BLE is not introduced here. The major focus here is to let you know BLE programming for Android.

BLE Working Flow

Generally the BLE programming on a smartphone or table works as a central device. It scans the peripheral devices and then connect to it. The connection then will be used to access the peripheral device's attributes/characteristics or wait for the notification from peripheral device. You can refer to the profile document to know more detail about how to access the attributes/characteristics.

Below I divided a complete BLE session into following pieces from the role of a central device.

1.      Scan BLE device
2.      Connect to a device
3.      Read/write BLE attributes (characteristics)
4.      Receive GATT notification (optional, based on the need of profile)

BLE Permission Declaration

Before starting the BLE programming, you have to declare enough permissions for  BLE operations on an Android device. Below are the permissions you should add in your App.

Declare the Bluetooth permission(s) in your application manifest file.

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>


If you want to declare that your app is available to BLE-capable devices only, include the following in your app's manifest:

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>


Android BLE API

Android starts to support BLE since 4.3 (API level 18). It introduced the Bluetooth LE related functions as below:
BLE scanning function was added in the existing class “BluetoothAdapter” which works originally for the traditional Bluetooth (2.0/3.0). More classes were also added to support BLE features  

Since Lollipop (API level 21), a new package “android.bluetooth.le” was introduced to address the BLE device scanning and advertising. The class “BluetoothLeScanner” is used to replace the Bluetooth LE scanning function

Device scanning:

(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

API level 18 ~ 20
BluetoothAdapter = BluetoothManager.getAdapter()
BluetoothAdapter.startLeScan()

API level 21 or later
BluetoothAdapter = BluetoothManager.getAdapter()
BluetoothLeScanner = BluetoothAdapter.getBluetoothLeScanner()
BluetoothLeScanner.startScan()

Device Connecting

To setup a connection, you need to create a service to receive the response of a service request.
Use bindService to bind this service with your activity. After it, the connectivity is managed by the event (intent) for connection, profile attributes, characteristic

That’s why we need to do 2 things before really starting the connecting.
-          Bind Service
-          Register Receivers to register all intents in the activities from the BLE service you bind.

ACTION_GATT_CONNECTED                          connected to a GATT server.
ACTION_GATT_DISCONNECTED                     disconnected from a GATT server.
ACTION_GATT_SERVICES_DISCOVERED                discovered GATT services.
ACTION_DATA_AVAILABLE                              received data from the device. This can be a result of read or notification operations.

BluetoothDevice = BluetoothAdapter.getRemoteDevice() // by giving device address
BluetoothGatt = BluetoothDevice.connectGatt()

Speedup the reconnection
BluetoothGatt.connect()


Read/write Attributes

-          After connecting to the remote GATT server, you can request to get the service
BluetoothGattService = BluetoothGatt.getServices()
-          When you get the service, you can use it to get its characteristic to read or write according to the definition in the profile.
BluetoothGattCharacteristic = BluetoothGattService.getCharacteristic()

Here I use the diagram below to illustrate the relationship of the classes.




Receive GATT notification (optional)






2013年10月26日 星期六

ARM vs x86 - 關於 Android 的硬體平台和相關的屬性設定


自 Android 問世以來,ARM 架構 CPU 一直是這個領域裡翹楚。不管是 Qualcomm, nVidia, MTK 還是 Samsung 的 Exynos CPU,幾乎都是以 ARM 架構所開發的。而 PC/NB 的老大 Intel,這幾年來看著 PC 和 NB 市場慢慢的走下坡,一直想重返 Mobile Device 這塊市場,也積極的推出新的產品,想要搶食這塊被啃食已久的大餅。尤其今年的 BayTrail 系列 Processor 來勢洶洶,砸下重金的招兵買馬,想和一直以來 PC/NB 的好朋友們一起合作推 Intel Inside 的平板。到底市場會有甚麼樣的反應頗令人期待,不過研發人員倒是已經為了 x86 架構的平台和 Android Market App 的相容性而大傷腦筋。


Instruction Set - ARM and x86

資工人學過 Computer Architecture 的人都知道,CPU Instruction set (指令集) 一直有 RISC 和 CISC 之爭

RISC = Reduced Instruction Set
CISC = Complex Instruction Set

RISC 界的代表就是 ARM,代表有 Qualcomm, nVidia, and MTK
CISC 界的代表就是 x86,代表有 Intel and AMD

通常簡化的說法是
CISC 的指令集複雜但功能比較強大,但也比較耗電
RISC 的指令集簡單但相對來說較省電
這樣的說法在這裏我們先不討論 (因為...  我也不是很清楚,之後再來找相關資料)
但有一點是非常清楚的,不同架構的 CPU 是不相容的
例如,以 ARM 指令集編譯的 binary,是無法在 x86 架構的 CPU 上執行

而 ARM 架構的 CPU 也因為不斷的演進,32-bit ARM 指令集又可大致分成
  • ARMv5
  • ARMv6
  • ARMv7
特別值得一提的是 ARMv7 開始加入了 FPU 硬體,也就是浮點運算的功能,
在 v5 和 v6 必須靠軟體的方式處理浮點運算,因此 v7 在浮點運算上的效能相對於 v5 和 v6 增進很多。
另外 v7 也加入了對 multi-cores 的 support。

每個版本又有不同的 variants,可參考下表:

ArchitectureBit
width
Cores designed by ARM HoldingsCores designed by 3rd partiesCortex profile
ARMv5
32
ARM7EJ, ARM9E, ARM10EXScale, FA626TE, Feroceon, PJ1/Mohawk
ARMv6
32
ARM11
ARMv6-M
32
ARM Cortex-M0, ARM Cortex-M0+, ARM Cortex-M1Microcontroller
ARMv7-M
32
ARM Cortex-M3
Microcontroller
ARMv7E-M
32
ARM Cortex-M4
Microcontroller
ARMv7-R
32
ARM Cortex-R4, ARM Cortex-R5, ARM Cortex-R7
Real-Time
ARMv7-A
32
ARM Cortex-A5, ARM Cortex-A7, ARM Cortex-A8,
ARM Cortex-A9, ARM Cortex-A12, ARM Cortex-A15
Krait, Scorpion, PJ4/Sheeva, Apple A6 / A6X (Swift)
Application
ARMv8-A
64
ARM Cortex-A53, ARM Cortex-A57X-Gene, Denver, Apple A7 (Cyclone)
Application
*上表的資料來源為 wiki 網站介紹 Arm Architecture 所截錄


Houdini -  A arm-to-x86  Translator

目前 Android Market 上還是以支援 ARM 的 App 居多
可能有人以為 Android App 是以 Java 語言開發的,所以只要有 Dalvik runtime 不就可以跨平台嗎?為什麼以 Java 為基礎的 App 還是跟平台有關?這就得提到 JNI and Android NDK 了。

JNI (Java Native Interface) 是一個特殊介面,他提供了 Java 一種方式可以呼叫 Native library 所提供的 functions。一般來說,native code 即是針對執行平台的作業系統和指令集所編譯而成的。比起 Java,就是少了 Dalvik runtime system 要 translate Dalvik bytecode 的 overhead,所得到的優勢就是 Performance 較好。因此一些有效能考量的應用常常會以 native library 的方式實作,以避免 Java 的 overhead 而拖累效能。Android NDK 便是 Android 提供的開發工具,用以開發 Android App 所要呼叫的 Native library。

依此,我們可以把 Android App 分成三種
  1. Android App with pure Java (完全用 Java)
  2. Android App + ARM native library
  3. Android App + x86 native library
當然也有結合 (2) + (3) 的。不過,目前還是以 (1) and (2) 的比例較高。
而且,遊戲類的 App 當中 (2) 的比例是非常高。
因此逼得 Intel 必須提供 Runtime translator,讓 (2) 這類的 App 能夠在 Intel 平台上運作。Houdini 就是為了這樣的目的而產生的一種 Runtime translator,他會在收到 App JNI request 時載入 ARM 的 native library,並動態的將 ARM instruction set 轉成 x86 instruction set。


Performance Index

上一段提到 Houdini 是一個 Runtime translator,聰明的你應該就意會到,他多多少少會產生 overhead 而影響的系統的效能。下面列出的是 App with ARM native library 在 x86 平台上執行會影響的部分:

App compatibility
其實現階段的 Houdini 已經能夠支援幾乎大部分的 Anrdoid App,但現實社會就是這麼的不完美,總是會有一些難搞的 App 不相容。
(但即使是 ARM 平台的 Android 也沒辦法做到 100%啊)
    App performance
    既然是 Translator,就表示他必須花費 resource (CPU+memory) 去做 arm to x86 轉換的動作,不過 Houdini 經過 Intel 的調教下,目前看起來在同樣的 App 下,使用 x86 native library 和使用 arm native library 的效能差異幾乎看不太出來。

    App launch time
    Launch time 的影響是因為當 ARM Native Library 被呼叫時,Houdini必須先把 library 載入並 parsing。
    Launch time 也是目前看來影響最多的。

    Power consumption impact
    由於多做了一些額外的事情,就有可能多消耗系統的功率,不過實際測試並不明顯,大約 2 ~ 3% 左右。


    Related Android Properties and Settings
    • ro.product.cpu.abi
    • ro.product.cpu.abi2
    • os.arch
    ABI 是 Appplication Binary Interface,簡單說就是系統所支援的指令集。
    Android 裡可設定 Primary ABI (abi) 和 Secondary ABI (abi2) 兩種
    Primary ABI 代表系統運作時主要使用的 binary code,不可為空白。
    Secondary ABI 代表系統運作時次要使用的 binary code,可為空白。

    以最通行的 ARM 架構為例  通常的設定如下:

    Example of ARM platform
    ro.product.cpu.abi = armeabi-v7a
    ro.product.cpu.abi2 = armeabi
    os.arch = arm

    Example of Intel x86
    ro.product.cpu.abi = x86
    ro.product.cpu.abi2 = armeabi
    os.arch = x86

    abi 和 abi2 的設定非常重要,他影響了 Android Package Manager 安裝 APK 時 native library 的安裝。

    從剛剛的討論中可發現,其實大部分的時候只需要處理好 abi and abi2 即可,
    但我們發現有時候某些 app 還會 check os.arch,推測可能是 App 對於非 ARM 架構的平台有可能有問題,用來防堵 x86 架構。


    小 心 得

    在目前還是以 ARM 平台為主的嵌入式系統,Intel 試圖以他熟悉的 x86 架構重返行動裝置系統,看起來似乎正掀起一片片漣漪。然而,這個市場並不是比誰的口袋深而已,Qualcomm 一直在高端裝置上有著非常好的成績,手上握有的 3G/4G 專利可以讓他躺著幹;而 MTK 在中低階市場上已經站穩腳步,不只大陸白牌廠,甚至越來越多知名手機品牌已採用其方案。其實平台方案是否能對的準系統廠商的胃才是重點,否則如果系統廠商沒辦法用 Intel 的平台讓消費者買單,砸再多錢也只是投向大海,期待 Intel 能夠建立好自己的生態鏈,畢竟這樣受益的也是消費者。

    2013年6月7日 星期五

    如何在 Android 上開發使用 Google Map V2 的 App

    寫於 2013/06/06 

    因為想在 Android App 上玩玩看 Google Map 的應用,所以開始研究如何把 Google Map 嵌入自己的 AP裡,整理自己研究後的心得和步驟如下:

    1. 開發環境安裝

    除了標準的 IDE 環境外{Eclipse},你還需要以下兩個 extra packages才能在你的環境裡開發 Google Map V2 相關的App,這兩個 packages 都可以透過 Android SDK Manager 下載到你的開發環境裡
    • Android support library
    • Google Play Service
    請開啟 Android SDK Manager,勾選紅色框起的兩個項目安裝


    2. 開啟 Google Map API 服務及 Key 的申請和安裝

    你需要到 Google Console 上作兩件事情
    • 開啟 Google Map API V2 服務
    • 用你的憑證所產生的SHA-1註冊你的 App,並得到 Google Map API V2 的 Key
    用你的 google 帳號 login Google Console 之後,你檢視他的服務項目可以發現,已經不能再用 Google Map API V1 的服務了


    接下來註冊你的 App 並取得 Key這個步驟比較麻煩,首先你必須要準備一個 SHA-1 Hash ,而這個 Hash 必須是從用來 Sign 你的 APK 的憑證所產生的,看了一堆文件都說要用 Java JDK 的 Keytool 來產生 SHA-1 Hash。但如果你是使用 Eclipse ,這邊有一個簡單的方式:

    首先點選 "Window" -> "Preferences" 叫出 Preferences 對話視窗,在對話視窗左邊選擇 "Android" -> "Build"




    Debug Keystore 是指你用來 sign APK 的 Key 的存放位置
    SHA-1 fingerprint 的內容即是你要拿去 Google Console 申請 Google Map API V2 的 Key 用的
    請注意,debug key 是 debug 階段拿來用的,一般正式出貨上架時會用另一組正式的 Key 來 Sign APK。因此,相對應的 API Key 也要用 release Key 所產生的 SHA-1去申請註冊。

    3. 新增新的專案,並匯入Google Play Service

    開啟 Eclipse 已準備新增一個 Android Application project,這時候你必須要了解 API Level 和 Google Map API 版本之間的關係。在 API Level 12 之後才支援 V2,所以你必須考慮好你所支援的 Android 版本,當你的 App 僅支援 API Level 12 之後,基本上只需要考慮一種狀況。如果你必須考慮運行於 API Level 11或更早之前的系統,仍然是可以的,只是必須多一些考量,這在第四點撰寫程式的時候會提到。

    Okay,你的專案已經新增好了,接下來在寫程式前要做好下面兩件事:
    • Import Google Play Service
    • Add Google Play service library in your project build environment 

    Press "File" -> "Import..." 開啟 Import 的對話視窗:


    選取 import 的 type 是 "Existing Android Code into Workspace",按下 "Next" button 會跳出 import 視窗,按下 "Browse" button 選取你剛剛安裝的 Google Play Service library,其路徑是在你的 SDK 安裝目錄裡的 "\extras\google\google_play_services\libproject\google-play-services_lib"。


    選完之後,即會出現如上圖紅色框框裡的 Google Play Service專案,勾選之後按下 "Next" button 及完成了 Google Play Service 的匯入。


    Press "Project" -> "Properties" 開啟 Android project properties 如下圖,選擇 "Android"。
    在視窗左下角按"Add" button 選擇要加入的 library


    你會看到綠色勾勾,如果哪時候看到的是紅色叉叉就代表有問題。
    記住 "Is Library" 那個 option 千萬不能勾選,那代表你的專案最後是要 build 成 library。
    按下 OK button 之後,代表你的 project build 已經可以使用指定的 library了。

    4. 撰寫程式碼

    這邊只是談論如何初步的把 Google Map 嵌入到你的 App,其他進階的應用待以後有空的時候再摸索。
    基本上分成兩部分:
    • 在 AndroidManifest.xml 中宣告需要的 permission 和 Google Map API Key
    • 在 Activity Layout file 中宣告 Google Map element 的位置

    關於 AndroidManifest.xml,範例如下:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.test.Maptest"
        android:versionCode="1" android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="12"
            android:targetSdkVersion="17" />
        <permission
            android:name="com.test.Maptest.permission.MAPS_RECEIVE"
            android:protectionLevel="signature"/>
        <uses-permission android:name="com.test.Maptest.permission.MAPS_RECEIVE"/>
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        <uses-feature
            android:glEsVersion="0x00020000"
            android:required="true"/>

        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name="com.test.Maptest.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <meta-data
                android:name="com.google.android.maps.v2.API_KEY"
                 android:value="YOUR_API_KEY"/>

        </application>
    </manifest>







    Layout file:

    <?xml version="1.0" encoding="utf-8"?>
    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    map:cameraBearing="45"
    map:cameraTargetLat="25.033611"
    map:cameraTargetLng="121.565000"
    map:cameraTilt="0"
    map:cameraZoom="13"
    map:mapType="normal"
    map:uiCompass="true"
    map:uiRotateGestures="true"
    map:uiScrollGestures="true"
    map:uiTiltGestures="true"
    map:uiZoomControls="false"
    map:uiZoomGestures="true"/>



    Reference

    Google Developer - Google Maps Android API v2
    Showing current location in Google Maps using API V2 with SupportMapFragment

    後 記

    為了搞定 Google Map API V2,前前後後摸索了很久,大部分的時間都花在只為了搞定 "gms.maps.MapFragment" ClassNotFound exception 這個問題。看了非常多的論壇討論,發現所有該加的都加了,也做了檢查再檢查,還是無解。最後大絕招是重開一次專案把上面的 3 和 4 重做一次,發現 ClassNotFound 的問題解決了!!

    我推測應該是在一開始摸索的時候東試試、西試試的,把某些系統的設定檔搞壞了,
    導致 apk build 出來的時候相關 GMS Map class 的參考路徑是錯的...