zoukankan      html  css  js  c++  java
  • InputMethodManagerService处理输入法——监听APK变动

    androidframeworksbaseservicesjavacomandroidserverInputMethodManagerService.java
    
    public InputMethodManagerService(Context context, WindowManagerService windowManager) {
        .......
    
            //构建IME通知栏显示信息
            mImeSwitcherNotification = new Notification();
            mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
            mImeSwitcherNotification.when = 0;
            mImeSwitcherNotification.flags = Notification.FLAG_ONGOING_EVENT;
            mImeSwitcherNotification.tickerText = null;
            mImeSwitcherNotification.defaults = 0; // please be quiet
            mImeSwitcherNotification.sound = null;
            mImeSwitcherNotification.vibrate = null;
    
            // Tag this notification specially so SystemUI knows it's important
            mImeSwitcherNotification.kind = new String[] { "android.system.imeswitcher" };
            //此Intent弹出选择输入法的Dialog
            Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
            mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
        ......
    
            //监听灭屏,亮屏
            final IntentFilter broadcastFilter = new IntentFilter();
            broadcastFilter.addAction(Intent.ACTION_SCREEN_ON);
            broadcastFilter.addAction(Intent.ACTION_SCREEN_OFF);
            broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
        ......
    
           //监听APK安装,卸载,不可用/可用,等变动
           mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
        ......
    
           //获取系统中输入法列表
           mSettings = new InputMethodSettings(
                    mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
        ......
            final String defaultImiId = mSettings.getSelectedInputMethod();
            if (DEBUG) {
                Slog.d(TAG, "Initial default ime = " + defaultImiId);
            }
            mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
    
            buildInputMethodListLocked(mMethodList, mMethodMap,
                    !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
            mSettings.enableAllIMEsIfThereIsNoEnabledIME();
    
           //监听Settings数据库
           mSettingsObserver = new SettingsObserver(mHandler);
    
        ......
           //监听系统语言变化
           final IntentFilter filter = new IntentFilter();
           filter.addAction(Intent.ACTION_LOCALE_CHANGED);
           mContext.registerReceiver(
                    new BroadcastReceiver() {
                        @Override
                        public void onReceive(Context context, Intent intent) {
                            synchronized(mMethodMap) {
                                resetStateIfCurrentLocaleChangedLocked();
                            }
                        }
                   }, 
    filter); }

    主要看一下对APK安装/卸载,不可用/可用,等变动的监听。 

    private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
    
    class MyPackageMonitor extends PackageMonitor {
    
            ......
    
            @Override
            public void onSomePackagesChanged() {
    
                ......
                         //判断输入法APK安装,卸载,然后更新IME
                            int change = isPackageDisappearing(imi.getPackageName());
                            if (isPackageModified(imi.getPackageName())) {
                                mFileManager.deleteAllInputMethodSubtypes(imiId);
                            }
                            if (change == PACKAGE_TEMPORARY_CHANGE
                                    || change == PACKAGE_PERMANENT_CHANGE) {
                                Slog.i(TAG, "Input method uninstalled, disabling: "
                                        + imi.getComponent());
                                setInputMethodEnabledLocked(imi.getId(), false);
                                
                            }
                ......
             }
    }

    PackageMonitor是系统源码中监听APP变动的现成代码。可以拿来直接用,贴上完整源码。

    androidframeworksasecorejavacomandroidinternalcontentPackageMonitor.java
    
    
    package com.android.internal.content;
    
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.Uri;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Looper;
    import android.os.UserHandle;
    import com.android.internal.os.BackgroundThread;
    
    import java.util.HashSet;
    
    /**
     * Helper class for monitoring the state of packages: adding, removing,
     * updating, and disappearing and reappearing on the SD card.
     */
    public abstract class PackageMonitor extends android.content.BroadcastReceiver {
        static final IntentFilter sPackageFilt = new IntentFilter();
        static final IntentFilter sNonDataFilt = new IntentFilter();
        static final IntentFilter sExternalFilt = new IntentFilter();
    
        static {
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
            sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
            sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
            sPackageFilt.addDataScheme("package");
            sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
            sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
            sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
            sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
        }
        
        final HashSet<String> mUpdatingPackages = new HashSet<String>();
        
        Context mRegisteredContext;
        Handler mRegisteredHandler;
        String[] mDisappearingPackages;
        String[] mAppearingPackages;
        String[] mModifiedPackages;
        int mChangeType;
        int mChangeUserId = UserHandle.USER_NULL;
        boolean mSomePackagesChanged;
    
        String[] mTempArray = new String[1];
    
        public void register(Context context, Looper thread, boolean externalStorage) {
            register(context, thread, null, externalStorage);
        }
    
        public void register(Context context, Looper thread, UserHandle user,
                boolean externalStorage) {
            if (mRegisteredContext != null) {
                throw new IllegalStateException("Already registered");
            }
            mRegisteredContext = context;
            if (thread == null) {
                mRegisteredHandler = BackgroundThread.getHandler();
            } else {
                mRegisteredHandler = new Handler(thread);
            }
            if (user != null) {
                context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
                context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
                if (externalStorage) {
                    context.registerReceiverAsUser(this, user, sExternalFilt, null,
                            mRegisteredHandler);
                }
            } else {
                context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
                context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
                if (externalStorage) {
                    context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
                }
            }
        }
    
        public Handler getRegisteredHandler() {
            return mRegisteredHandler;
        }
    
        public void unregister() {
            if (mRegisteredContext == null) {
                throw new IllegalStateException("Not registered");
            }
            mRegisteredContext.unregisterReceiver(this);
            mRegisteredContext = null;
        }
        
        //not yet implemented
        boolean isPackageUpdating(String packageName) {
            synchronized (mUpdatingPackages) {
                return mUpdatingPackages.contains(packageName);
            }
        }
        
        public void onBeginPackageChanges() {
        }
    
        /**
         * Called when a package is really added (and not replaced).
         */
        public void onPackageAdded(String packageName, int uid) {
        }
    
        /**
         * Called when a package is really removed (and not replaced).
         */
        public void onPackageRemoved(String packageName, int uid) {
        }
    
        /**
         * Called when a package is really removed (and not replaced) for
         * all users on the device.
         */
        public void onPackageRemovedAllUsers(String packageName, int uid) {
        }
    
        public void onPackageUpdateStarted(String packageName, int uid) {
        }
    
        public void onPackageUpdateFinished(String packageName, int uid) {
        }
    
        /**
         * Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED
         * Intent.ACTION_PACKAGE_CHANGED} being received, informing you of
         * changes to the enabled/disabled state of components in a package
         * and/or of the overall package.
         *
         * @param packageName The name of the package that is changing.
         * @param uid The user ID the package runs under.
         * @param components Any components in the package that are changing.  If
         * the overall package is changing, this will contain an entry of the
         * package name itself.
         * @return Return true to indicate you care about this change, which will
         * result in {@link #onSomePackagesChanged()} being called later.  If you
         * return false, no further callbacks will happen about this change.  The
         * default implementation returns true if this is a change to the entire
         * package.
         */
        public boolean onPackageChanged(String packageName, int uid, String[] components) {
            if (components != null) {
                for (String name : components) {
                    if (packageName.equals(name)) {
                        return true;
                    }
                }
            }
            return false;
        }
        
        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
            return false;
        }
    
        public void onHandleUserStop(Intent intent, int userHandle) {
        }
        
        public void onUidRemoved(int uid) {
        }
        
        public void onPackagesAvailable(String[] packages) {
        }
        
        public void onPackagesUnavailable(String[] packages) {
        }
        
        public static final int PACKAGE_UNCHANGED = 0;
        public static final int PACKAGE_UPDATING = 1;
        public static final int PACKAGE_TEMPORARY_CHANGE = 2;
        public static final int PACKAGE_PERMANENT_CHANGE = 3;
    
        /**
         * Called when a package disappears for any reason.
         */
        public void onPackageDisappeared(String packageName, int reason) {
        }
    
        /**
         * Called when a package appears for any reason.
         */
        public void onPackageAppeared(String packageName, int reason) {
        }
    
        /**
         * Called when an existing package is updated or its disabled state changes.
         */
        public void onPackageModified(String packageName) {
        }
        
        public boolean didSomePackagesChange() {
            return mSomePackagesChanged;
        }
        
        public int isPackageAppearing(String packageName) {
            if (mAppearingPackages != null) {
                for (int i=mAppearingPackages.length-1; i>=0; i--) {
                    if (packageName.equals(mAppearingPackages[i])) {
                        return mChangeType;
                    }
                }
            }
            return PACKAGE_UNCHANGED;
        }
        
        public boolean anyPackagesAppearing() {
            return mAppearingPackages != null;
        }
        
        public int isPackageDisappearing(String packageName) {
            if (mDisappearingPackages != null) {
                for (int i=mDisappearingPackages.length-1; i>=0; i--) {
                    if (packageName.equals(mDisappearingPackages[i])) {
                        return mChangeType;
                    }
                }
            }
            return PACKAGE_UNCHANGED;
        }
        
        public boolean anyPackagesDisappearing() {
            return mDisappearingPackages != null;
        }
        
        public boolean isPackageModified(String packageName) {
            if (mModifiedPackages != null) {
                for (int i=mModifiedPackages.length-1; i>=0; i--) {
                    if (packageName.equals(mModifiedPackages[i])) {
                        return true;
                    }
                }
            }
            return false;
        }
        
        public void onSomePackagesChanged() {
        }
        
        public void onFinishPackageChanges() {
        }
    
        public int getChangingUserId() {
            return mChangeUserId;
        }
    
        String getPackageName(Intent intent) {
            Uri uri = intent.getData();
            String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
            return pkg;
        }
        
        @Override
        public void onReceive(Context context, Intent intent) {
            mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                    UserHandle.USER_NULL);
            if (mChangeUserId == UserHandle.USER_NULL) {
                throw new IllegalArgumentException(
                        "Intent broadcast does not contain user handle: " + intent);
            }
            onBeginPackageChanges();
            
            mDisappearingPackages = mAppearingPackages = null;
            mSomePackagesChanged = false;
            
            String action = intent.getAction();
            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                String pkg = getPackageName(intent);
                int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
                // We consider something to have changed regardless of whether
                // this is just an update, because the update is now finished
                // and the contents of the package may have changed.
                mSomePackagesChanged = true;
                if (pkg != null) {
                    mAppearingPackages = mTempArray;
                    mTempArray[0] = pkg;
                    if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                        mModifiedPackages = mTempArray;
                        mChangeType = PACKAGE_UPDATING;
                        onPackageUpdateFinished(pkg, uid);
                        onPackageModified(pkg);
                    } else {
                        mChangeType = PACKAGE_PERMANENT_CHANGE;
                        onPackageAdded(pkg, uid);
                    }
                    onPackageAppeared(pkg, mChangeType);
                    if (mChangeType == PACKAGE_UPDATING) {
                        synchronized (mUpdatingPackages) {
                            mUpdatingPackages.remove(pkg);
                        }
                    }
                }
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                String pkg = getPackageName(intent);
                int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
                if (pkg != null) {
                    mDisappearingPackages = mTempArray;
                    mTempArray[0] = pkg;
                    if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                        mChangeType = PACKAGE_UPDATING;
                        synchronized (mUpdatingPackages) {
                            //not used for now
                            //mUpdatingPackages.add(pkg);
                        }
                        onPackageUpdateStarted(pkg, uid);
                    } else {
                        mChangeType = PACKAGE_PERMANENT_CHANGE;
                        // We only consider something to have changed if this is
                        // not a replace; for a replace, we just need to consider
                        // it when it is re-added.
                        mSomePackagesChanged = true;
                        onPackageRemoved(pkg, uid);
                        if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) {
                            onPackageRemovedAllUsers(pkg, uid);
                        }
                    }
                    onPackageDisappeared(pkg, mChangeType);
                }
            } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
                String pkg = getPackageName(intent);
                int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
                String[] components = intent.getStringArrayExtra(
                        Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
                if (pkg != null) {
                    mModifiedPackages = mTempArray;
                    mTempArray[0] = pkg;
                    mChangeType = PACKAGE_PERMANENT_CHANGE;
                    if (onPackageChanged(pkg, uid, components)) {
                        mSomePackagesChanged = true;
                    }
                    onPackageModified(pkg);
                }
            } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
                mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                mChangeType = PACKAGE_TEMPORARY_CHANGE;
                boolean canRestart = onHandleForceStop(intent,
                        mDisappearingPackages,
                        intent.getIntExtra(Intent.EXTRA_UID, 0), false);
                if (canRestart) setResultCode(Activity.RESULT_OK);
            } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
                mDisappearingPackages = new String[] {getPackageName(intent)};
                mChangeType = PACKAGE_TEMPORARY_CHANGE;
                onHandleForceStop(intent, mDisappearingPackages,
                        intent.getIntExtra(Intent.EXTRA_UID, 0), true);
            } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
                onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0));
            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                if (intent.hasExtra(Intent.EXTRA_USER_HANDLE)) {
                    onHandleUserStop(intent, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                mAppearingPackages = pkgList;
                mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
                        ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
                mSomePackagesChanged = true;
                if (pkgList != null) {
                    onPackagesAvailable(pkgList);
                    for (int i=0; i<pkgList.length; i++) {
                        onPackageAppeared(pkgList[i], mChangeType);
                    }
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                mDisappearingPackages = pkgList;
                mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)
                        ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE;
                mSomePackagesChanged = true;
                if (pkgList != null) {
                    onPackagesUnavailable(pkgList);
                    for (int i=0; i<pkgList.length; i++) {
                        onPackageDisappeared(pkgList[i], mChangeType);
                    }
                }
            }
            
            if (mSomePackagesChanged) {
                onSomePackagesChanged();
            }
            
            onFinishPackageChanges();
            mChangeUserId = UserHandle.USER_NULL;
        }
    }
    View Code

    在实现监听APK安装,卸载时,可能用不到PackageMonitor中那么详细的处理。

    但是要注意

    final IntentFilter sPackageFilt = new IntentFilter();
    sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
            sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
            sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
            sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
    sPackageFilt.addDataScheme("package");//这个是必须要有的,否则监听不到。

    如果在AndroidManifest.xml中配置广播监听APK变动

            <receiver android:name="MyReceiver" >   
                <intent-filter>  
                    <action android:name="android.intent.action.PACKAGE_ADDED" />  
                    <action android:name="android.intent.action.PACKAGE_REMOVED" />  
                    <action android:name="android.intent.action......." /> 
                    <action android:name="android.intent.action......." /> 
                    <data android:scheme="package" />  <!--注意这行一定要加-->
                </intent-filter>  
            </receiver>          
  • 相关阅读:
    oracle中Blob和Clob类型的区别
    为什么要分库分表
    Enable file editing in Visual Studio's debug mode
    SQL Server Dead Lock Log
    Debug .NET Framework Source
    SQL Server text field里面有换行符的时候copy到excel数据会散乱
    诊断和修复Web测试记录器(Web Test Recorder)问题
    Can't load Microsoft.ReportViewer.ProcessingObjectModel.dll
    'telnet' is not recognized as an internal or external command
    Linq to XML
  • 原文地址:https://www.cnblogs.com/antoon/p/4250758.html
Copyright © 2011-2022 走看看