1. 程式人生 > >安卓5.0新加輔助功能(高對比性文字/色彩校正/顏色反轉)學習

安卓5.0新加輔助功能(高對比性文字/色彩校正/顏色反轉)學習

摘要

在安卓L版本中,輔助設定中新加了3個功能,分別是高對比性文字,顏色反轉,色彩校正




高對比性文字

  • 先來看看google是怎麼說這個功能的
This information applies only to devices running Android 5.0 and higher.

High contrast makes text easier to read on your device. This feature fixes the text color as either black or white, depending on the original text color.

To enable or disable high contrast text, follow these steps:
Go to Settings > Accessibility
. Select High contrast text. High-contrast text is currently an experimental feature, so it might not work correctly everywhere on your device.
  • 再來看看效果圖
google說,這個功能就是讓文字更容易閱讀,也就是有點類似與文字高亮。最後的效果就是,把文字變成白色或黑色,把背景文字背景變成黑色或白色
也就是說,如果你之前的文字是白色,背景是黑色,就不會去應用這個功能,即使開啟了,就想上面設定的actionbar
  • 最後看看怎麼實現的,簡單分析
從上圖可以看出,最後文字為何會這樣顯示,是因為在操作ViewRootImpl,遍歷view,重新繪製。當然上圖可能不是很完整,因為重繪前還需要view中之前的狀態,比如之前的顏色什麼的。
不過,我們大概已經知道,只要實現是通過修改ViewRootImpl來達到系統中所有view都能顯示成這個效果的目的


顏色反轉

  • 先看看google是怎麼說這個功能的
This information applies only to devices running Android 5.0 and higher.

Color inversion exchanges color values. For example, black text on a white screen becomes white text on a black screen.

To enable or disable color inversion, follow these steps:
Go to Settings > Accessibility
. Select Color inversion. Color inversion is currently an experimental feature, so it might not work correctly everywhere on your device.
  • 再來看看效果圖
 下面兩幅圖是在瀏覽器頁面,第一副是未開啟顏色反轉功能的,第二幅是開啟顏色反轉後的。
開啟顏色反轉後,所有的地方都會出現上述效果
從上面的效果圖上看出,這個功能與有的瀏覽器推出的夜間模式很像。
也就是說,我們可以通過這個功能達到晚上玩手機不會刺眼,可以模擬出夜晚效果
  • 最後來看看實現,簡單分析
這是開啟顏色反轉的時序圖
再跳轉到後面看開啟色彩校正後的時序圖,會發現這兩個操作後的流程是一樣的



色彩校正

  • 先看看google是怎麼說這個功能的
This information applies only to devices running Android 5.0 and higher.

The color correction setting enables your device to compensate for color blindness.

To enable or disable color correction, follow these steps:
Go to Settings > Accessibility > Color correction.
Set the switch to the on or off position.
To change the color correction mode, select Correction mode, then choose one of the following options:
Deuteranomaly (red-green)
Protanomaly (red-green)
Tritanomaly (blue-yellow)

Color correction is currently an experimental feature, so it might not work correctly everywhere on your device.
  • 再來看看效果圖
下面四幅圖是在launcher介面,為了讓效果更明顯,安裝了360 launcher,將app按照圖示顏色分類
第一副是未開啟顏色校正的
第二副是開啟後,選擇紅弱視,會發現紅色的圖示變暗了
第二副是開啟後,選擇綠弱視,會發現綠色的圖示變暗了
第二副是開啟後,選擇藍弱視,會發現藍色的圖示變暗了
根據google說明,該功能是給色盲色弱的提供。
我這裡還不是很明白,選擇紅弱視後,紅色變暗了;紅弱視本生在較亮的環境下是可以看清楚的,變暗後不是更看不清了嗎!!
  • 最後來看看實現,簡單分析
這是開啟色彩校正後的時序圖


  • 先簡單說下顏色反轉和色彩校正的實現原理
通過SurfaceFlinger去控制gpu改變螢幕的顯示效果,給你視覺上的錯覺,控制元件本身並沒有被改變。
高對比性文字是修改了控制元件,而這兩個功能只是給你顯示上的錯覺,開啟後,截圖放到電腦看到的仍然是未開啟時的效果
  • 顏色反轉和色彩校正流程原理分析
無論是顏色反轉還是色彩校正,都會在資料庫(SettingsProvider)中儲存一個值。
AccessibilityManagerService這個類就是為輔助功能服務的
AccessibilityManagerService會去註冊一個監聽,監聽輔助功能中哪些值被改變了
當開啟顏色校正或顏色反轉後,AccessibilityManagerService就會監聽到,然後按照上面的時序圖執行
AccessibilityManagerService會呼叫DisplayAdjustmentUtils的applyAdjustments方法
在這個方法裡會執行multiply,setDaltonizerMode,setColorTransform
multiply方法中主要用於計算顏色矩陣
    private static float[] multiply(float[] matrix, float[] other) {
        if (matrix == null) {
            return other;
        }
        float[] result = new float[16];
        Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
        return result;
    }
setDaltonizerMode方法主要用於設定模擬模式
可以看出該方法會通過binder連線到SurfaceFlinger,將mode傳遞過去
    /**
     * Sets the surface flinger's Daltonization mode. This adjusts the color
     * space to correct for or simulate various types of color blindness.
     *
     * @param mode new Daltonization mode
     */
    private static void setDaltonizerMode(int mode) {
        try {
            final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
            if (flinger != null) {
                final Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                data.writeInt(mode);
                flinger.transact(1014, data, null, 0);
                data.recycle();
            }
        } catch (RemoteException ex) {
            Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex);
        }
    }
setColorTransform主要用於設定顏色轉換
可以看出該方法會通過binder連線到SurfaceFlinger,將一個顏色矩陣傳遞過去
 /**
     * Sets the surface flinger's color transformation as a 4x4 matrix. If the
     * matrix is null, color transformations are disabled.
     *
     * @param m the float array that holds the transformation matrix, or null to
     *            disable transformation
     */
    private static void setColorTransform(float[] m) {
        try {
            final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
            if (flinger != null) {
                final Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                if (m != null) {
                    data.writeInt(1);
                    for (int i = 0; i < 16; i++) {
                        data.writeFloat(m[i]);
                    }
                } else {
                    data.writeInt(0);
                }
                flinger.transact(1015, data, null, 0);
                data.recycle();
            }
        } catch (RemoteException ex) {
            Slog.e(LOG_TAG, "Failed to set color transform", ex);
        }
    }

接著會呼叫SurfaceFlinger的onTransact方法
setDaltonizerMode傳過來的code值是1014
setColorTransform傳過來的code值是1015
當設定顏色反轉時,mode為-1,也就是說會執行mDaltonizer.setMode(Daltonizer::simulation);
當設定顏色校正時,mode會大於10(11紅弱視,12綠弱視,13藍弱視),會執行mDaltonizer.setMode(Daltonizer::correction);也會設定相應的type
case 1015中會將setColorTransform傳遞過來的顏色矩陣拿出來,doDisplayComposition方法會通過shader讓gpu顯示出效果
最後呼叫repaintEverything重繪
 frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
 status_t SurfaceFlinger::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
         ......省略數行......
         switch (code) {
		 ......省略數行......
             case 1014: {
                 // daltonize
                 n = data.readInt32();
                 switch (n % 10) {
                     case 1: mDaltonizer.setType(Daltonizer::protanomaly);   break;
                     case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break;
                     case 3: mDaltonizer.setType(Daltonizer::tritanomaly);   break;
                 }
                 if (n >= 10) {
                     mDaltonizer.setMode(Daltonizer::correction);
                 } else {
                     mDaltonizer.setMode(Daltonizer::simulation);
                 }
                 mDaltonize = n > 0;
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
             }
             case 1015: {
                 // apply a color matrix
                 n = data.readInt32();
                 mHasColorMatrix = n ? 1 : 0;
                 if (n) {
                     // color matrix is sent as mat3 matrix followed by vec3
                     // offset, then packed into a mat4 where the last row is
                     // the offset and extra values are 0
                     for (size_t i = 0 ; i < 4; i++) {
                       for (size_t j = 0; j < 4; j++) {
                           mColorMatrix[i][j] = data.readFloat();
                       }
                     }
                 } else {
                     mColorMatrix = mat4();
                 }
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
             }
            ......省略數行...... 
         }
     }
     return err;
 }
 
 frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
        const Region& inDirtyRegion)
 {
     ......
 
     if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
         if (!doComposeSurfaces(hw, dirtyRegion)) return;
     } else {
         RenderEngine& engine(getRenderEngine());
         mat4 colorMatrix = mColorMatrix;
         if (mDaltonize) {
             colorMatrix = colorMatrix * mDaltonizer();
         }
         engine.beginGroup(colorMatrix);
         doComposeSurfaces(hw, dirtyRegion);
         engine.endGroup();
     }
      ......
 }
最後看看模擬器
 frameworks/native/services/surfaceflinger/Effects/Daltonizer.h
class Daltonizer {
 public:
     enum ColorBlindnessTypes {
         protanopia,         // L (red) cone missing 紅色盲
         deuteranopia,       // M (green) cone missing 綠色盲
         tritanopia,         // S (blue) cone missing 藍色盲
         protanomaly,        // L (red) cone deficient 紅色弱
         deuteranomaly,      // M (green) cone deficient (most common) 綠色弱
         tritanomaly         // S (blue) cone deficient 藍色弱
     };
 
     enum Mode {
         simulation, //模擬,開啟顏色反轉後模式
         correction  //校正,開啟色彩校正後模式
     };
 ......


小結

高對比性文字主要是修改控制元件,顏色反轉和顏色校正主要是通過操作gpu修改顯示效果