1. 程式人生 > >22 展訊Sprd設定-電池-識別輸入法應用

22 展訊Sprd設定-電池-識別輸入法應用

1. 目的

輸入法應用屬於可識別型別且核心應用,不能進行攔截和kill

2. 展訊輸入法判斷

2.1 判斷邏輯塊

    //handle inputmethod
    if (isLaunchingIMEApp(intent, targetApp, targetUid, callerApp, reason)) {
        return true;
    }

2.2 判斷是否為輸入法

    private boolean isLaunchingIMEApp(Intent intent, String targetApp, int targetUid,
            String callerApp, String reason) {

        //handle inputmethod
        // 是否滿足以下條件
        // 1. caller 為系統發起
        // 2. 啟動型別為bind-services
        // 3. action為輸入法型別
        if ("android".equals(callerApp)
            && REASON_BIND_SERVICE.equals(reason)
            && intent != null && "android.view.InputMethod".equals(intent.getAction())) {

            // 判斷為輸入法應用
            if (targetApp != null) { // a input method
                // 如果未儲存到當前可用輸入法,則存入mEnabledInputMethodAppList列表中
                int index = mEnabledInputMethodAppList.indexOf(targetApp);
                if (index < 0) {
                    mEnabledInputMethodAppList.add(targetApp);

                    // 多使用者模式下,儲存輸入法資訊到對應列表中
                    int userId = UserHandle.getUserId(targetUid);
                    mAppStateInfoCollector.updateAppInputMethodState(targetApp, true, userId);
                    mAppStateInfoCollector.setDefaultInputMethodApp(targetApp, userId);
                }
            }
            return true;
        }

        // allow to start input Method
        // 是否滿足下面條件
        // 1. 啟動型別為bind-services
        // 2. caller 為系統發起
        // 3. 該程序屬於輸入法列表
        if (REASON_BIND_SERVICE.equals(reason) && "android".equals(callerApp) && isInputMethodApp(targetApp)) {
            if (DEBUG) Slog.d(TAG, "isLaunchingIMEApp: "+targetApp
                + ", callingPackage = "+callerApp+", reason = "+reason +" allow for input method");
            return true;
        }

        return false;
    }
    
    // input method app
    private boolean isInputMethodApp(String pkgName) {
        int index = mEnabledInputMethodAppList.indexOf(pkgName);
        if (index >= 0) {
            return true;
        }
        return false;
    }

2.3 AppStateInfoCollector.updateAppInputMethodState

更新對應程序狀態中,應用狀態mIsEnabledInputMethod為輸入法應用

    // update the Input Method identify state of this app
    public void updateAppInputMethodState(String pkgName, boolean isInputMethod, int userId) {
        ArrayMap<String, AppState> mAppStateInfoList = getAppStateInfoList(userId);
        int index = mAppStateInfoList.indexOfKey(pkgName);
        if (index >= 0) {
            AppState appState = mAppStateInfoList.valueAt(index);
            appState.mIsEnabledInputMethod = isInputMethod;
        }
    }

2.4 AppStateInfoCollector.setDefaultInputMethodApp

更新為預設輸入法

    // update the Input Method identify state of this app
    public void setDefaultInputMethodApp(String pkgName, int userId) {
        ArrayMap<String, AppState> mAppStateInfoList = getAppStateInfoList(userId);
        String mDefaultIMEAppName =  mDefaultIMEAppNameForUsers.get(userId);

        // 新值與預設輸入法一致,則不需要重複更新
        if (mDefaultIMEAppName != null
            && mDefaultIMEAppName.equals(pkgName)) {
            return;
        }

        // 舊的預設輸入法更新狀態
        // clear orignal
        if (mDefaultIMEAppName != null) {
            int index = mAppStateInfoList.indexOfKey(mDefaultIMEAppName);
            if (index >= 0) {
                AppState appState = mAppStateInfoList.valueAt(index);
                appState.mIsDefaultInputMethod = false;
            }
        }

        // set new
        // 新值設定為預設輸入法即當前使用的輸入法
        int index = mAppStateInfoList.indexOfKey(pkgName);
        if (index >= 0) {
            AppState appState = mAppStateInfoList.valueAt(index);
            appState.mIsDefaultInputMethod = true;
        }

        mDefaultIMEAppName = pkgName;
        mDefaultIMEAppNameForUsers.put(userId, mDefaultIMEAppName);
    }

2.5 APPstate建立中會進行判斷是否為輸入法

    // check if is input method
    retVal.mIsEnabledInputMethod = isEnabledIMEApp(packageName);
        
    // if this app is a input Method
    private boolean isEnabledIMEApp(String pkgName){
        if (pkgName == null) return false;
        IInputMethodManager service = IInputMethodManager.Stub.asInterface(
            ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
        List<InputMethodInfo> inputMethods;
        try {
            inputMethods = service.getEnabledInputMethodList();
        } catch (RemoteException e) {
            return false;
        }
        if (inputMethods == null || inputMethods.size() == 0) return false;
        for (InputMethodInfo info : inputMethods){
            if (info == null || info.getPackageName() == null) continue;
            if (info.getPackageName().equals(pkgName)) return true;
        }
        return false;
    }    

3. 應用上層的輸入法判斷

3.1 判斷是否為預設輸入法,或者正在使用的當前輸入法

    public static String getInputPackage(Context mContext) {
        String result = null;
        String input = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
        if (input == null || input.equals("") || !input.contains("/")) {
            // frameworks/base/packages/SettingsProvider/res/values/defaults.xml, default_input_method
        } else {
            result = input.substring(0, input.indexOf('/'));
        }
        Log.d(TAG, "getInputPackage = " + result);
        return result;
    }

3.2 根據AndroidManifest進行判斷是否為輸入法

    public static boolean isInputMethodApp(Context context, String packageName) {
        PackageManager pm = context.getPackageManager();
        boolean isInputMethodApp = false;
        try {
            PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES);
            ServiceInfo[] sInfo = pkgInfo.services;
            if (sInfo != null) {
                for (int i = 0; i < sInfo.length; i++) {
                    ServiceInfo serviceInfo = sInfo[i];
                    if (serviceInfo.permission != null && serviceInfo.permission.equals("android.permission.BIND_INPUT_METHOD")) {
                        isInputMethodApp = true;
                        break;
                    }
                }
            }
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return isInputMethodApp;
    }

3.3 根據 InputMethodManager 進行獲取輸入法列表

    public static ArrayList<String> getInputMethodAppList(Context context) {
        ArrayList<String> list = new ArrayList<String>();
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);

        List<InputMethodInfo> methodList = imm.getInputMethodList();
        List<String> mInputMethodBlackList = getInputMethodBlackList(context);

        if (methodList != null) {
            for (InputMethodInfo mi : methodList) {
                String inputMethodPackageName = mi.getPackageName();

                if (!mInputMethodBlackList.contains(inputMethodPackageName)) {
                    list.add(inputMethodPackageName);
                }

            }
        }
        Log.d(TAG, "getInputMethodAppList = " + list.toString());
        return list;
    }