SystemUI插件化流程分析

SystemUI插件化流程分析

SystemUI插件

SystemUI 插件提供了一种快速创建 SystemUI 功能原型的简便方法,可以在运行时更改 SystemUI 的行为。 通过创建插件实现 SysUI 中使用的一组基本接口来完成,然后可以比当前更快的速度迭代由该接口控制的部分代码。

底层逻辑

SystemUIApplication.startServicesIfNeeded

Dependency 是定义在 config_systemUIServiceComponents 这个 config 文件中的,在 startServicesIfNeeded 中会遍历此 config 定义的所有 SystemUI 重要类,调用它们的Start方法:

private void startServicesIfNeeded(String[] services) {

        Dependency.get(InitController.class).executePostInitTasks();

        log.traceEnd();

        final Handler mainHandler = new Handler(Looper.getMainLooper());

        //调用addPluginListener传入了三个参数,PluginListener,

        //OverlayPlugin.class,和一个boolean值true

        Dependency.get(PluginManager.class).addPluginListener(

                new PluginListener<OverlayPlugin>() {

                    private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();

                    @Override

                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {

                        

                        mainHandler.post(new Runnable() {

                            @Override

                            public void run() {

                                StatusBar statusBar = getComponent(StatusBar.class);

                                if (statusBar != null) {

                                    plugin.setup(statusBar.getStatusBarWindow(),

                                            statusBar.getNavigationBarView(), new Callback(plugin));

                                }

                            }

                        });

                    }

                    @Override

                    public void onPluginDisconnected(OverlayPlugin plugin) {

                        mainHandler.post(new Runnable() {

                            @Override

                            public void run() {

                                mOverlays.remove(plugin);

                                Dependency.get(StatusBarWindowController.class).setForcePluginOpen(

                                        mOverlays.size() != 0);

                            }

                        });

                    }

                    class Callback implements OverlayPlugin.Callback {

                        private final OverlayPlugin mPlugin;

                        Callback(OverlayPlugin plugin) {

                            mPlugin = plugin;

                        }

                        @Override

                        public void onHoldStatusBarOpenChange() {

                            if (mPlugin.holdStatusBarOpen()) {

                                mOverlays.add(mPlugin);

                            } else {

                                mOverlays.remove(mPlugin);

                            }

                            mainHandler.post(new Runnable() {

                                @Override

                                public void run() {

                                    Dependency.get(StatusBarWindowController.class)

                                            .setStateListener(b -> mOverlays.forEach(

                                                    o -> o.setCollapseDesired(b)));

                                    Dependency.get(StatusBarWindowController.class)

                                            .setForcePluginOpen(mOverlays.size() != 0);

                                }

                            });

                        }

                    }

                }, OverlayPlugin.class, true /* Allow multiple plugins */);

        mServicesStarted = true;

    }

Dependency.start

@Override

public void start() {

    // TODO: Think about ways to push these creation rules out of Dependency to cut down

    // on imports.

    mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);

    mProviders.put(BG_LOOPER, mBgLooper::get);

    mProviders.put(BG_HANDLER, mBgHandler::get);

    mProviders.put(MAIN_HANDLER, mMainHandler::get);

    mProviders.put(ActivityStarter.class, mActivityStarter::get);

    mProviders.put(ActivityStarterDelegate.class, mActivityStarterDelegate::get);

    mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get);

    mProviders.put(BluetoothController.class, mBluetoothController::get);

    mProviders.put(SensorPrivacyManager.class, mSensorPrivacyManager::get);

    mProviders.put(LocationController.class, mLocationController::get);

    mProviders.put(RotationLockController.class, mRotationLockController::get);

    mProviders.put(NetworkController.class, mNetworkController::get);

    mProviders.put(ZenModeController.class, mZenModeController::get);

    mProviders.put(HotspotController.class, mHotspotController::get);

    mProviders.put(CastController.class, mCastController::get);

    mProviders.put(FlashlightController.class, mFlashlightController::get);

    mProviders.put(KeyguardMonitor.class, mKeyguardMonitor::get);

    mProviders.put(UserSwitcherController.class, mUserSwitcherController::get);

    mProviders.put(UserInfoController.class, mUserInfoController::get);

    mProviders.put(BatteryController.class, mBatteryController::get);

    ......

    sDependency = this;

}

Dependency.get

get方法最终通过mDependencies.get来获取对象,mDependencies是个ArrayMap,如果没有获取到就调用createDependency创建对象,创建之后放入mDependencies中

private static Dependency sDependency;

@Deprecated

public static <T> T get(Class<T> cls) {

    return sDependency.getDependency(cls);

}

protected final <T> T getDependency(Class<T> cls) {

    return getDependencyInner(cls);

}

private synchronized <T> T getDependencyInner(Object key) {

    @SuppressWarnings("unchecked")

    T obj = (T) mDependencies.get(key);

    if (obj == null) {

        obj = createDependency(key);

        mDependencies.put(key, obj);

    }

    return obj;

}

createDependency

此方法通过mProviders.get来获取对象,mProviders中的类就是在Start方法中添加的,所以能够直接获取,Dependency中用到了dagger框架的Lazy,Provider等机制。

@VisibleForTesting

protected <T> T createDependency(Object cls) {

    @SuppressWarnings("unchecked")

    LazyDependencyCreator<T> provider = mProviders.get(cls);

    if (provider == null) {

        throw new IllegalArgumentException("Unsupported dependency " + cls

                                           + ". " + mProviders.size() + " providers known.");

    }

    return provider.createDependency();

}

addPluginListener

综上所述,Dependency.get(T.class)就可以简单认为是获取T的实现类

SystemUIApplication的startServicesIfNeeded方法添加插件监听,这里实际调用PluginManagerImpl的addPluginListener方法,此方法接收三个参数:一个PluginListener接口,一个Class对象,一个boolean值

可以看到共有 4 个重载方法,此处调用的为第2个重载方法,获取action之后调用了第 4 个重载方法

public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) {

    addPluginListener(listener, cls, false);

}

public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,

                                                 boolean allowMultiple) {

    addPluginListener(PluginManager.Helper.getAction(cls), listener, cls, allowMultiple);

}

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,

                                                 Class<?> cls) {

    addPluginListener(action, listener, cls, false);

}

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,

                                                 Class cls, boolean allowMultiple) {

    android.util.Log.d("djtang","addPluginListener...action = :"+action+",name = :"+cls.getName());

    mPluginPrefs.addAction(action);

    PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,

                                                                   allowMultiple, mLooper, cls, this);

    p.loadAll();

    mPluginMap.put(listener, p);

    startListening();

}

PluginListener

PluginListener这个接口,这是个泛型接口,其中T必须是Plugin的子类,此接口提供两个生命周期方法,插件连接时调用onPluginConnected,断开连接调用onPluginDisconnected

public interface PluginListener<T extends Plugin> {

   

    void onPluginConnected(T plugin, Context pluginContext);

    

    default void onPluginDisconnected(T plugin) {

    }

}

PluginManager.Helper.getAction(cls)

通过getDeclaredAnnotation方法获取注解,ProvidesInterface这是个注解类,每个继承Plugin的类包含一个ProvidesInterface,这个注解类包含两项,version和action

public interface PluginManager {

	class Helper {

        public static <P> String getAction(Class<P> cls) {

        	//获取ProvidesInterface的注解信息

            ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);

            if (info == null) {

                throw new RuntimeException(cls + " doesn't provide an interface");

            }

            if (TextUtils.isEmpty(info.action())) {

                throw new RuntimeException(cls + " doesn't provide an action");

            }

            //获取ProvidesInterface注解的action

            return info.action();

        }

}

public @interface ProvidesInterface {

    int version();

    String action() default "";

}

用法

@ProvidesInterface(action = MyPlugin.ACTION, version = MyPlugin.VERSION)

public interface MyPlugin extends Plugin {

    String ACTION = "com.android.systemui.action.PLUGIN_MY_PLUGIN";

    int VERSION = 1;

    ...

}

// 小米代码在com.android.systemui.plugins.miui.qs

再看第 4 个重载方法

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,

                                                 Class cls, boolean allowMultiple) {

    mPluginPrefs.addAction(action);

    PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, 

                                           action, listener,allowMultiple, mLooper, cls, this);

    p.loadAll();

    mPluginMap.put(listener, p);

    startListening();

}

首先将action添加到mPluginPrefs,mPluginPrefs是一个PluginPrefs,它的内部有一个ArraySet和一个SharedPreferences,它的存储机制就是将action先存储到ArraySet,再将此ArraySet存到SharedPreferences中,具体代码就不贴出了

接着mFactory.createPluginInstanceManager方法,mFactory是PluginInstanceManagerFactory类型,是PluginManagerImpl的静态内部类

@VisibleForTesting

public static class PluginInstanceManagerFactory {

    public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,

                                                                                String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,

                                                                                Class<?> cls, PluginManagerImpl manager) {

        return new PluginInstanceManager(context, action, listener, allowMultiple, looper,

                                         new VersionInfo().addClass(cls), manager);

    }

}

createPluginInstanceManager其实就是new了一个PluginInstanceManager对象,

接着调用了PluginInstanceManager的loadAll方法

PluginInstanceManager.loadAll()

通过handler处理消息

public void loadAll() {

    if (DEBUG) Log.d(TAG, "startListening");

    mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);

}

该handler用的是子线程,其looper用的是非主线程looper

PluginInstanceManager(Context context, PackageManager pm, String action,

            PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,

            PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {

    mMainHandler = new MainHandler(Looper.getMainLooper());

    mPluginHandler = new PluginHandler(looper);

}

QUERY_ALL

private class PluginHandler extends Handler {

    private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();

    public void handleMessage(Message msg) {

        switch (msg.what) {

            case QUERY_ALL:

                if (DEBUG) Log.d(TAG, "queryAll " + mAction);

                //如果mPlugins不为空,则遍历mPlugins,调用onPluginDisconnected

                //清理Plugin

                for (int i = mPlugins.size() - 1; i >= 0; i--) {

                    PluginInfo<T> plugin = mPlugins.get(i);

                    mListener.onPluginDisconnected(plugin.mPlugin);

                    if (!(plugin.mPlugin instanceof PluginFragment)) {

                        plugin.mPlugin.onDestroy();

                    }

                }

                //清空mPlugins

                mPlugins.clear();

                handleQueryPlugins(null);

                break;

        }

    }

}

handleQueryPlugins

private void handleQueryPlugins(String pkgName) {

            

    Intent intent = new Intent(mAction);

    //pkgName == null,此处的intent只有action,没有pkgName

    if (pkgName != null) {

        intent.setPackage(pkgName);

    }

    //給定intent,返回满足条件的ResolveInfo(本质是service)集合

    List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);

    if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");

    //mAllowMultiple == true,不会走进去

    if (result.size() > 1 && !mAllowMultiple) {

        Log.w(TAG, "Multiple plugins found for " + mAction);

        if (DEBUG) {

            for (ResolveInfo info : result) {

                ComponentName name = new ComponentName(info.serviceInfo.packageName,

                                                       info.serviceInfo.name);

                Log.w(TAG, "  " + name);

            }

        }

        return;

    }

    //遍历ResolveInfo

    for (ResolveInfo info : result) {

        ComponentName name = new ComponentName(info.serviceInfo.packageName,

                                               info.serviceInfo.name);

        //根据info信息创建插件

        PluginInfo<T> t = handleLoadPlugin(name);

        if (t == null) continue;

        //如果成功创建了PluginInfo就添加到mPlugins保存

        mPlugins.add(t);

        //将创建好的PluginInfo发送到主线程处理

        mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();

    }

}

PLUGIN_CONNECTED

private class MainHandler extends Handler {

	public void handleMessage(Message msg) {

            switch (msg.what) {

                case PLUGIN_CONNECTED:

                    if (DEBUG) Log.d(TAG, "onPluginConnected");

                    PluginPrefs.setHasPlugins(mContext);

                    //将handler发送过来的obj强转为PluginInfo

                    PluginInfo<T> info = (PluginInfo<T>) msg.obj;

                    mManager.handleWtfs();

                    //如果是Fragment类型的Plugin

                    if (!(msg.obj instanceof PluginFragment)) {

                      	//调用它的onCreate方法

                        info.mPlugin.onCreate(mContext, info.mPluginContext);

                    }

                    //调用onPluginConnected方法

                    mListener.onPluginConnected(info.mPlugin, info.mPluginContext);

                    break;

                    ......

	}

}

1. mPluginHandler在后台线程处理消息,在收到QUERY_ALL消息后如果有Plugin则先判断是否是Fragment类型Plugin,如果是则调用onDestroy方法,还会调用Plugin添加的PluginListener的回调onPluginDisconnected

2. mMainHandler在主线程处理mPluginHandler发送来的Plugin,同样判断如果是Fragment类型Plugin则调用onCreate,还会调用Plugin添加的PluginListener的回调onPluginConnected

经过上面的分析,我们知道了PluginInstanceManager是一个专门用来管理Plugin的类,每个Plugin对应一个

public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,

            Class cls, boolean allowMultiple) {

    mPluginPrefs.addAction(action);

    PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,

                                                                   allowMultiple, mLooper, cls, this);

    p.loadAll();

    mPluginMap.put(listener, p);

    startListening();

}

mPluginMap是一个ArrayMap,将同一个Plugin的listener和PluginInstanceManager一一对应的保存进去

private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap

            = new ArrayMap<>();

startListening()

private void startListening() {

    //保证只启动一次

    if (mListening) return;

    mListening = true;

    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);

    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);

    filter.addAction(Intent.ACTION_PACKAGE_REPLACED);

    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);

    filter.addAction(PLUGIN_CHANGED);

    filter.addAction(DISABLE_PLUGIN);

    filter.addDataScheme("package");

    mContext.registerReceiver(this, filter);

    filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);

    mContext.registerReceiver(this, filter);

}

注册广播,在收到广播时,交由reciever处理

public void onReceive(Context context, Intent intent) {

	if(Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())){

		......

	}else if(DISABLE_PLUGIN.equals(intent.getAction())){

		......

	}else {

           .....

           if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {

                for (PluginInstanceManager manager : mPluginMap.values()) {

                    manager.onPackageChange(pkg);

                }

            } else {

                for (PluginInstanceManager manager : mPluginMap.values()) {

                    manager.onPackageRemoved(pkg);

                }

            }

	}

}

else分支中如果是ACTION_PACKAGE_REMOVED广播则调用

manager.onPackageRemoved,否则调用manager.onPackageChange,这两个方法在PluginInstanceManager类中,其实它们是一对相对应的方法,一个onPackageRemoved最终会调到PluginListener的onPluginDisconnected中,

onPackageChange最终会调到PluginListener的onPluginConnected中

PluginInstanceManager

onPackageChange中相当于先调了一次onPackageRemoved

public void onPackageRemoved(String pkg) {

    mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();

}

    

public void onPackageChange(String pkg) {

    mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();

    mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkg).sendToTarget();

}

QUERY_PKG和REMOVE_PKG

private class PluginHandler extends Handler {

	public void handleMessage(Message msg) {

		switch (msg.what) {

			case REMOVE_PKG:

                    mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,

                                    plugin.mPlugin).sendToTarget();

                    break;

			case QUERY_PKG:

                    String p = (String) msg.obj;

                    handleQueryPlugins(p);

                    .....

                    break;

              } 

	}

}

REMOVE_PKG中向MainHandler主线程发送了PLUGIN_DISCONNECTED的msg,QUERY_PKG中调用了handleQueryPlugins方法,此方法前面已经分析过了,最终是向MainHandler主线程发送了PLUGIN_CONNECTED的msg

private class MainHandler extends Handler {

    switch (msg.what) {

        case PLUGIN_CONNECTED:

            ......

            mListener.onPluginConnected(info.mPlugin, info.mPluginContext);

            break;

        case PLUGIN_DISCONNECTED:

            mListener.onPluginDisconnected((T) msg.obj);

            ......

            break;

    }

}

mListener.onPluginConnected(info.mPlugin, info.mPluginContext);

private PluginListener mQsTilePluginListener = new PluginListener<MiuiQSTilePlugin>() {

        @Override

        public void onPluginConnected(MiuiQSTilePlugin plugin, Context pluginContext) {

            // 处理插件, 获取插件内容

            // 前面获取到所有的插件后, 遍历插件实例化, 并且通过消息发送, 触发回调

            mMiuiQSTilsplugin = plugin;

            mPluginStockTiles = plugin.getStockTileWithOrder();

            mPluginDefaultTiles = plugin.getDefaultTileWithOrder();

            mQsStockTiles = TextUtils.isEmpty(mPluginStockTiles) ? mQsStockTiles : mPluginStockTiles;

            mQsDefaultTiles = TextUtils.isEmpty(mPluginDefaultTiles) ? mQsDefaultTiles : mPluginDefaultTiles;

            filterIndependentTiles();

            onTuningChanged();

        }

        @Override

        public void onPluginDisconnected(MiuiQSTilePlugin plugin) {

            mMiuiQSTilsplugin = null;

            initQSTiles(mContext);

            onTuningChanged();

        }

    };

onTuningChanged()

private void onTuningChanged() {

     onTuningChanged(mTileListKey, "");

     // getTileListValue()获取前面写进内存里的mQsDefaultTiles值.即plugin中自定义的插件名

     // 格式"wifi, camara" 名称中间用逗号隔开

     onTuningChanged(mTileListKey, getTileListValue());

 }

public void onTuningChanged(String key, String newValue) {

 		...

    // 将插件名通过识别逗号,解析成string的list

    final List<String> tileSpecs = loadTileSpecs(mContext, newValue);

 	// 新建map用于存储解析出来的插件

    final LinkedHashMap<String, QSTile> newTiles = new LinkedHashMap<>();

    for (String tileSpec : tileSpecs) {

        QSTile tile = mTiles.get(tileSpec);

        // 前面回调触发2次, 第一次用于重置,第二次用于新建

        if (tile != null && (!(tile instanceof CustomTile)

                             || ((CustomTile) tile).getUser() == currentUser)) {

            if (tile.isAvailable()) {

                if (DEBUG) Log.d(TAG, "Adding " + tile);

                tile.removeCallbacks();

                if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {

                    tile.userSwitch(currentUser);

                }

                newTiles.put(tileSpec, tile);

            } else {

                Slog.d(TAG, "onTuningChanged: unavailable tile: " + tile);

                tile.destroy();

            }

        } else {

            if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);

            if (tile != null) {

                tile.destroy();

            }

            try {

                tile = createTile(tileSpec);

                if (tile != null) {

                    if (tile.isAvailable()) {

                        tile.setTileSpec(tileSpec);

                        newTiles.put(tileSpec, tile);

                    } else {

                        Slog.d(TAG, "onTuningChanged: unavailable custom tile: " + tile);

                        tile.destroy();

                    }

                }

            } catch (Throwable t) {

                Slog.w(TAG, "onTuningChanged: Error creating tile for spec: " + tileSpec, t);

            }

        }

    }

    mCurrentUser = currentUser;

    List<String> currentSpecs = new ArrayList(mTileSpecs);

    mTileSpecs.clear();

    mTileSpecs.addAll(tileSpecs);

    mTiles.clear();

    mTiles.putAll(newTiles);

    ...

}

小米的比较特殊, listener的回调中, 触发了2次onTuningChanged

根据其注释及代码理解, 第一次用于解绑所有的插件, 第二次用于重新创建插件

mTiles 用于存储已创建插件, 视图上的事件绑定和显示都将用到这个list

createTile(tileSpec)

public QSTile createTile(String tileSpec) {

        // Use Extreme battery saver instead of SuperPower if extreme battery saver supported.

        if (tileSpec.equals("custom(com.miui.securitycenter/com.miui.superpower.notification.SuperPowerTileService)")

                && (!(ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM)

                    || (Constants.IS_INTERNATIONAL && Constants.SUPPORT_EXTREME_BATTERY_SAVER && !Constants.IS_TABLET))) {

            return null;

        }

        if (tileSpec.equals("custom(com.miui.screenrecorder/.service.QuickService)")

                && !(ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM)) {

            return null;

        }

        for (int i = 0; i < mQsFactories.size(); i++) {

            QSTile t = mQsFactories.get(i).createTile(tileSpec, mControlTileHost);

            if (t != null) {

                return t;

            }

        }

        return null;

    }

通过插件名创建插件对象

工厂方法,最终走到QSFactoryImpl.createTile(String tileSpec)

private QSTileImpl createTileInternal(String tileSpec) {

        MiuiQSTilePlugin miuiQSTilePlugin = mHost.getMiuiQSTilePlugin();

        HashMap<String, MiuiQSTile> map = null;

        if (miuiQSTilePlugin != null) {

            map = (HashMap) miuiQSTilePlugin.getAllPluginTiles();

        }

        if (map != null && map.containsKey(tileSpec)) {

            // 三方插件走到这里

            return new PluginTile(mHost, map.get(tileSpec));

        } else if (tileSpec.equals("wifi")) return new WifiTile(mHost);

        else if (tileSpec.equals("bt")) return new BluetoothTile(mHost);

        else if (tileSpec.equals("cell")) return new CellularTile(mHost);

        else if (tileSpec.equals("airplane")) return new AirplaneModeTile(mHost);

        else if (tileSpec.equals("rotation")) return new RotationLockTile(mHost);

        else if (tileSpec.equals("flashlight")) return new FlashlightTile(mHost);

        else if (tileSpec.equals("gps")) return Build.VERSION.SDK_INT > 28 ? new LocationTile(mHost) : new GpsTile(mHost);

        ...

    }

可以看到部分插件是写死在这里的, 直接返回创建的特定的对象,但是三方插件都是通过miuiQSTilePlugin.getAllPluginTiles()方法获取到自定义的PluginTileMap,并通过tileSpec这个key去查找对应的对象,最后生成通用对象PluginTile()

我们来看一下之前小米实现的Plugin接口

@ProvidesInterface(action = MiuiQSTilePlugin.ACTION, version = MiuiQSTilePlugin.VERSION)

public interface MiuiQSTilePlugin extends Plugin {

    String ACTION = "com.android.systemui.action.PLUGIN_MIUI_QS_TILE";

    int VERSION = 1;

    //get default tile order,it will override the local default tile order

    String getDefaultTileWithOrder();

    //get stock tile order,it will override the local stock tile order

    String getStockTileWithOrder();

    //get all plugin tiles,to achieve function of tilePlugins.The map key is tilespec.

    Map<String, MiuiQSTile> getAllPluginTiles();

}

这里可以看到, 要求插件必须继承并实现  getAllPluginTiles()方法,下面举一个实现的例子

@Requires(target = MiuiQSTilePlugin.class, version = MiuiQSTilePlugin.VERSION)

public class LocalMiuiQSTilePlugin implements MiuiQSTilePlugin {

    private Context mPluginContext;

    private Context mSysuiContext;

    HashMap<String, MiuiQSTile> mAllMiuiTilesMap;

    @Override

    public void onCreate(Context sysuiContext, Context pluginContext) {

        mSysuiContext = sysuiContext;

        mPluginContext = pluginContext;

        initAllMiuiTilesPlugin();

    }

    private void initAllMiuiTilesPlugin() {

        mAllMiuiTilesMap = new HashMap<>();

        FreeFormHangTile freeFormHangTile = new FreeFormHangTile(mSysuiContext, mPluginContext);

        mAllMiuiTilesMap.put(freeFormHangTile.getTileSpec(), freeFormHangTile);

        ScannerTile scannerTile = new ScannerTile(mSysuiContext, mPluginContext);

        mAllMiuiTilesMap.put(scannerTile.getTileSpec(), scannerTile);

    }

    @Override

    public Map<String, MiuiQSTile> getAllPluginTiles() {

        return mAllMiuiTilesMap;

    }

    @Override

    public String getDefaultTileWithOrder() {

        return mPluginContext.getString(R.string.quick_settings_tiles_default);

    }

    @Override

    public String getStockTileWithOrder() {

        return mPluginContext.getString(R.string.quick_settings_tiles_stock);

    }

    @Override

    public void onDestroy() {

    }

}

简单来说, 即三方插件需要继承MiuiQSTilePlugin,并实现其对应方法

其中2种方法用于获取三方插件中需要添加的插件名称及排序方式

getAllPluginTiles用于获取插件名称和实现对象的对应关系.

SVG开源库解析 2023-03-14
【转】Android 实现书籍翻页效果----原理篇 2023-07-12

评论区