美文网首页
QSTitle创建流程

QSTitle创建流程

作者: 音苍 | 来源:发表于2016-09-03 16:41 被阅读1216次

    本文将分析Android6.0中下拉状态栏快捷开关QSTitle组件的创建流程,从开机init过程开始至具体的每个QSTitle对象具体的创建,如何添加入下拉状态栏,对QSTitle的相关整体流程进行梳理。

    android设备上电,引导程序引导进入boot(通常是uboot),加载initramfs、kernel镜像,启动kernel后,进入用户态程序。第一个用户空间程序是init, PID固定是1.
    在android系统上,init.cpp的代码位于/system/core/init下,基本功能有:

    • 管理设备
    • 解析并处理Android启动脚本init.rc
    • 实时维护这个init.rc中的服务,包括加载 Zygote

    这里不过过多分析init.cpp部分,重点关注Zygote的启动流程。init,cpp部分推荐相关文档http://my.oschina.net/youranhongcha/blog/469028

    init.rc配置文件在 Android 6.0 代码中位于 system/core/rootdir
    /init.zygote32.rc,具体内容为:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd
        writepid /dev/cpuset/foreground/tasks
    

    其中:

    1. 关键字 service 表示告诉 init 进程创建名为 zygote 的进程,所要执行的程序是 /system/bin/app_process,后面的都是传递的参数。
    2. 注意参数 --start-system-server,说明要启动 SystemServer
    3. socket zygote stream 660 root system 表示创建名为 zygote 的 socket。
    4. 后面的 onrestart 关键字表示 zygote 进程重启时所需执行的命令。

    Zygote 的启动

    从中我们可以得出结论: zygote 只是服务的名称,与此服务对应的程序是 app_process 程序,我们研究 zygote 的实现,就是要研究 app_process 程序。
    app_process 代码位于 frameworks/base/cmds/app_process
    /app_main.cpp,入口函数为 main。
    main 的大体流程为:

    • 创建一个 AppRuntime 实例 runtime
    • 解析传入的命令行参数
    • 判断调用哪一个 runtime.start,传入对应的参数
    • 由于 init.zygote32.rc 中传入参数 -Xzygote /system/bin --zygote --start-system-server,因此将执行:
      runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

    由此可知,app_process 没干什么主要的事情,只是跳转到 Java 类 com.android.internal.os.ZygoteInit,看来工作都在 ZygoteInit 中完成。但ZygoteInit如何启动呢?
    我们来看看AppRuntime 。

    AndroidRuntime

    runtime.start方法来自于 AppRuntime 的父类 AndroidRuntime,代码位于 frameworks/base/core/jni/AndroidRuntime.cpp。重点看看 AndroidRuntime start 方法,它主要做了三件事:

    首先是创建虚拟机:

    /* start the virtual machine */
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env, zygote) != 0) {
            return;
        }
        onVmCreated(env);
    

    之后是调用 startReg 函数注册 JNI 方法:

    /*
         * Register android functions.
         */
        if (startReg(env) < 0) {
            ALOGE("Unable to register all android natives\n");
            return;
        }
    

    最后构建参数、创建 JNI 类对象,获取 main 方法,并最终执行下面一行执行 main 入口:

      env->CallStaticVoidMethod(startClass, startMeth, strArray);
    

    这样我们就成功从 AndroidRuntime.cpp中启动了一个虚拟机,并加载了 Java 类 ZygoteInit,并进入到它的 main 方法中执行。

    ZygoteInit

    之后就来到了 ZygoteInit.java 的 main 方法,代码位frameworks/
    base/core/java/com/android/internal/os/ZygoteInit.java。来看其 main 方法:

    public static void main(String argv[]) {
       try {
           ...
           registerZygoteSocket(socketName);
           ...
           if (startSystemServer) {
               startSystemServer(abiList, socketName);
           }
           ...
           runSelectLoop(abiList);
           ...
       } catch (...) { ... }
    }
    

    首先,调用 registerZygoteSocket 创建了一个名为 zygote 的 socket:

    registerZygoteSocket(socketName);
    

    之后启动 SystemServer 组件:

    if (startSystemServer) {
    startSystemServer(abiList, socketName);
    }
    

    最后调用 runSelectLoopMode 进入一个死循环,等待接受 socket 上由 ActivityManagerService 发来的请求创建应用程序的请求:

    runSelectLoop(abiList);
    

    对后startSystemServer(abiList, socketName);进行分析:
    启动 SystemServer 组件
    SystemServer 名为系统服务进程,负责启动 Android 系统的关键服务。来看看函数的主要实现:

    private static boolean startSystemServer(String abiList, String socketName)
           throws MethodAndArgsCaller, RuntimeException {
        ...
        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
            parsedArgs.uid, parsedArgs.gid,
            parsedArgs.gids,
            parsedArgs.debugFlags,
            null,
            parsedArgs.permittedCapabilities,
            parsedArgs.effectiveCapabilities);
        ...
        /* For child process */
        if (pid == 0) {
            ...
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }
    

    这里调用了 Zygote 的静态方法 forkSystemServer 来创建 SystemServer 进程。
    在forkSystemServer 中进行JNI调用forkSystemServer - com_android_internal_os_Zygote_nativeForkSystemServer - ForkAndSpecializeCommon来成功fork一个新进程。
    子进程创建好之后,有一句

    handleSystemServerProcess(parsedArgs);
    

    进入handleSystemServerProcess:

    /**
         * Finish remaining work for the newly forked system server process.
         */
        private static void handleSystemServerProcess(
                ZygoteConnection.Arguments parsedArgs)
                throws ZygoteInit.MethodAndArgsCaller {
        ...
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        ...
        if (...) {
            ...
        } else {
          ClassLoader cl = null;
          if (systemServerClasspath != null) {
              cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
              Thread.currentThread().setContextClassLoader(cl);
          }
    
          /*
           * Pass the remaining arguments to SystemServer.
           */
          RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    

    从中可以看出,我们从环境变量 SYSTEMSERVERCLASSPATH 拿到 SystemServer 的类名,之后载入进来,最后使用 RuntimeInit.zygoteInit 来运行,它来执行 SystemServer 的 main 方法。

    看一下RuntimeInit.zygoteInit():

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        ...
        commonInit();   // 基本设置(异常捕获、时区、HTTP User-Agent 等)
        nativeZygoteInit();
        applicationInit(targetSdkVersion, argv, classLoader); // 调用 Main 方法
    }
    

    其中 nativeZygoteInit() 是一个 jni 调用,位于 AndroidRuntime.cpp:

    static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
    {
        gCurRuntime->onZygoteInit();
    }
    

    onZygoteInit() 是 AppRuntime 中的方法,具体为:

    virtual void onZygoteInit()
    {
       sp<ProcessState> proc = ProcessState::self();
       ALOGV("App process: starting thread pool.\n");
       proc->startThreadPool();
    }
    

    启动了一个线程池。nativeZygoteInit() 就分析到这里,由此可见,Zygote 启动 SystemServer 的过程就算完了,之后的,都是 SystemServer 内部的事情了。

    SystemServer.main()

    上面说到RuntimeInit.zygoteInit 来执行 SystemServer.main方法。我们来看SystemServer.main():

    /**
         * The main entry point from zygote.
         */
        public static void main(String[] args) {
            new SystemServer().run();
        }
    

    生成SystemServer对象并跳转到了run();
    去run()看看:

    private void run() {
        ......
        
         // Start services.
            try {
                startBootstrapServices();
                startCoreServices();
                startOtherServices();
                ......
           } catch (Throwable ex) {
               ...
                throw ex;
            }
            ...
            // Loop forever.
            Looper.loop();
            throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    

    在这里启动了一些服务,我们重点去看startBootstrapServices();

      private void startBootstrapServices() {
            ......
            Installer installer = mSystemServiceManager.startService(Installer.class);
    
            // Activity manager runs the show.
            mActivityManagerService = mSystemServiceManager.startService(
                    ActivityManagerService.Lifecycle.class).getService();
            mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
            ......
     }
    
    

    Activity manager运行
    再回到SystemServer,run()有这么一句:

    startOtherServices();
    

    startOtherServices()代码:

    private void startOtherServices() {
            final Context context = mSystemContext;
            AccountManagerService accountManager = null;
            ContentService contentService = null;
            .......
            
             mActivityManagerService.systemReady(new Runnable() {
                @Override
                public void run() {
                  ......
    
                    try {
                        startSystemUi(context);
                    } catch (Throwable e) {
                        reportWtf("starting System UI", e);
                    }
             .......
    

    在这里mActivityManagerService.systemReady创建线程去调用startSystemUi(context);

    static final void startSystemUi(Context context) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.android.systemui",
                        "com.android.systemui.SystemUIService"));
            //Slog.d(TAG, "Starting service: " + intent);
            context.startServiceAsUser(intent, UserHandle.OWNER);
        }
    

    通过intent.setComponent(new ComponentName("com.android.systemui",
    "com.android.systemui.SystemUIService"));
    设置启动systemui程序的SystemUIService
    进入SystemUIService:

    public class SystemUIService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            ((SystemUIApplication) getApplication()).startServicesIfNeeded();
        }
    ......
    
    

    onCreate方法中获得SystemUIApplication对象并调用其startServicesIfNeeded方法:

     public void startServicesIfNeeded() {
            final int N = SERVICES.length;
            for (int i=0; i<N; i++) {
                Class<?> cl = SERVICES[i];
                try {
                    mServices[i] = (SystemUI)cl.newInstance();//加载实例
                } catch (IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                } catch (InstantiationException ex) {
                    throw new RuntimeException(ex);
                }
                mServices[i].mContext = this;
                mServices[i].mComponents = mComponents;
                mServices[i].start();//start服务
                if (mBootCompleted) {
                    mServices[i].onBootCompleted();
                }
            }
            mServicesStarted = true;
        }
    

    这个方法中,首先判断mServicesStarted标志为来判断SystemUI相关的服务是否启动,
    同时根据系统配置文件来检查ActivityManagerService是否finishBooting。
    可以看到这里有个mServices数组,并通过for循环加载它们的实例并调用它们的start();
    但是mServices数组具体开启了哪些服务呢?
    来看看SystemUIApplication类中的变量:

    private final Class<?>[] SERVICES = new Class[] {
                com.android.systemui.tuner.TunerService.class,
                com.android.systemui.keyguard.KeyguardViewMediator.class,
                com.android.systemui.recents.Recents.class,
                com.android.systemui.volume.VolumeUI.class,
                com.android.systemui.statusbar.SystemBars.class,
                com.android.systemui.usb.StorageNotification.class,
                com.android.systemui.power.PowerUI.class,
                com.android.systemui.media.RingtonePlayer.class,
                com.android.systemui.keyboard.KeyboardUI.class,
        };
    

    可以看到这里有很多sysytemui中常用的服务,后面将重点分析SystemBars及TunerService。
    直接进入SystemBars.start():

    public void start() {
            mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                    mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
            mServiceMonitor.start();  // will call onNoService if no remote service is found
        }
    

    start中创建ServiceMonitor实例并start();
    注释中说明,/服务没启动时,ServiceMonitor会回调SystemBars的onNoService/
    所以去看SystemBars的onNoService:

    public void onNoService() {
            createStatusBarFromConfig();  // fallback to using an in-process implementation
        }
    

    直接去看createStatusBarFromConfig():

    private void createStatusBarFromConfig() {
            final String clsName = mContext.getString(R.string.config_statusBarComponent);
            if (clsName == null || clsName.length() == 0) {
                throw andLog("No status bar component configured", null);
            }
            Class<?> cls = null;
            try {
                cls = mContext.getClassLoader().loadClass(clsName);
            } catch (Throwable t) {
                throw andLog("Error loading status bar component: " + clsName, t);
            }
            try {
                mStatusBar = (BaseStatusBar) cls.newInstance();
            } catch (Throwable t) {
                throw andLog("Error creating status bar component: " + clsName, t);
            }
            mStatusBar.mContext = mContext;
            mStatusBar.mComponents = mComponents;
            mStatusBar.start();
        }
    

    clsName得到的string为com.android.systemui.statusbar.phone.PhoneStatusBar
    通过反射机制得到PhoneStatusBar实例:

    cls = mContext.getClassLoader().loadClass(clsName);
    ...
    mStatusBar = (BaseStatusBar) cls.newInstance();
    

    并调用start方法:
    PhoneStatusBar继承自BaseStatusBar;
    PhoneStatusBar中调用了BaseStatusBar的start()
    BaseStatusBar.start():

    public void start() {
            mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
            mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
            mDisplay = mWindowManager.getDefaultDisplay();
            mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                    Context.DEVICE_POLICY_SERVICE);
    
            mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
    
            mNotificationData = new NotificationData(this);
    
            mAccessibilityManager = (AccessibilityManager)
                    mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    
            mDreamManager = IDreamManager.Stub.asInterface(
                    ServiceManager.checkService(DreamService.DREAM_SERVICE));
            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    
            .......
            //在这里实例化了许多systemui常用的对象,服务,Manager,Observer等等
            .......
            
            createAndAddWindows(); //本本文而言一个非常重要的方法
            
    

    查看createAndAddWindows():

     protected abstract void createAndAddWindows();
    

    是个抽象方法,很显然调用去了BaseStatusBar的子类中,即PhoneStatusBar中
    PhoneStatusBar的createAndAddWindows():

     @Override
     public void createAndAddWindows() {
            addStatusBarWindow();
     }
     
     private void addStatusBarWindow() {
            makeStatusBarView();//关键方法,创建StatusBarView
            mStatusBarWindowManager = new StatusBarWindowManager(mContext);
            mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
     }
    
    

    可以看到这里最终调用了makeStatusBarView方法:

    protected PhoneStatusBarView makeStatusBarView() {
            final Context context = mContext;
    
            Resources res = context.getResources();
    
            updateDisplaySize(); // populates mDisplayMetrics
            updateResources();
    
            mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                    R.layout.super_status_bar, null);
            ........
            mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
            mStatusBarView.setBar(this);
    
            PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
            mStatusBarView.setPanelHolder(holder);
    
            mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                    R.id.notification_panel);
            mNotificationPanel.setStatusBar(this);
    
            if (!ActivityManager.isHighEndGfx()) {
                mStatusBarWindow.setBackground(null);
                mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                        R.color.notification_panel_solid_background)));
            }
            ........
            
            mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
            mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
            mKeyguardBottomArea =
                    (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
            ........
            //可以看到这里完成了许多systemui关键组件的view创建。这个方法很重要。
            ........
            // Set up the quick settings tile panel
            mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
            if (mQSPanel != null) {
                final QSTileHost qsh = new QSTileHost(mContext, this,
                        mBluetoothController, mLocationController, mRotationLockController,
                        mNetworkController, mZenModeController, mHotspotController,
                        mCastController, mFlashlightController,
                        mUserSwitcherController, mKeyguardMonitor,
                        mSecurityController,
                        mAudioProfileController
                        );
                mQSPanel.setHost(qsh);
                mQSPanel.setTiles(qsh.getTiles());   
                mHeader.setQSPanel(mQSPanel);
                qsh.setCallback(new QSTileHost.Callback() {
                    @Override
                    public void onTilesChanged() {
                        mQSPanel.setTiles(qsh.getTiles());
                    }
                });
            }
            .........
    

    看到QSPanel,发现了我们的目标,它是下拉状态栏的一个关键类。
    在mQSPanel加载xml布局之后,创建QSTileHost对象。
    直接去看QSTileHost的继承关系及构造方法:

    public class QSTileHost implements QSTile.Host, Tunable {
        .......
        //这里QSTileHost继承了Tunable接口,下文将有一个非常经典的java回调实现
    
    
    public QSTileHost(Context context, PhoneStatusBar statusBar,
    
            ........
            
              TunerService.get(mContext).addTunable(this, TILES_SETTING);
              //回调实现的第一步
              //这里传了this。
              //将继承了Tunable接口的QSTileHost传递给TunerService的addTunable();
              
        }
    
    

    重点即为TunerService的addTunable。TunerService看起来有点眼熟,向上查看文章,它和systembars一起
    在SystemUIApplication中被实例化并开启
    来看TunerService的addTunable:

    public void addTunable(Tunable tunable, String... keys) {
            for (String key : keys) {
                addTunable(tunable, key);
            }
        }
    
        private void addTunable(Tunable tunable, String key) {
            if (!mTunableLookup.containsKey(key)) {
                mTunableLookup.put(key, new ArrayList<Tunable>());
            }
            mTunableLookup.get(key).add(tunable);
            Uri uri = Settings.Secure.getUriFor(key);
            if (!mListeningUris.containsKey(uri)) {
                mListeningUris.put(uri, key);
                mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
            }
            // Send the first state.
            String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
            //这里的value将获得一个长字符,包含了所有系统QSTitle组件名,在后面进行分割,生成具体的QSTitle对象
            //例子:  wifi,location,dataconnection,hotspot,audioprofile,bt,rotation,airplane,screenshot
            tunable.onTuningChanged(key, value);//回调第二步,addTunable传递来的QSTileHost对象调用自己的onTuningChanged方法
        }
    

    来看QSTileHost的onTuningChanged()

    @Override
        public void onTuningChanged(String key, String newValue) {
            if (!TILES_SETTING.equals(key)) {
                return;
            }
            final List<String> tileSpecs = loadTileSpecs(newValue);//切割传递来的newValue为List
            if (tileSpecs.equals(mTileSpecs)) return;
            for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
                if (!tileSpecs.contains(tile.getKey())) {
                    tile.getValue().destroy();
                }
            }
            final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
            for (String tileSpec : tileSpecs) {
                if (mTiles.containsKey(tileSpec)) {
                    newTiles.put(tileSpec, mTiles.get(tileSpec));
                } else {
                    if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
                    try {
                        newTiles.put(tileSpec, createTile(tileSpec));
                        //createTile()中根据上文切割出的QSTitle名创建相应的对象
                    } catch (Throwable t) {
                    }
                }
            }
            mTileSpecs.clear();
            mTileSpecs.addAll(tileSpecs);
            mTiles.clear();
            mTiles.putAll(newTiles);
            if (mCallback != null) {
                mCallback.onTilesChanged();
            }
        }
    

    看看createTile(tileSpec)

    protected QSTile<?> createTile(String tileSpec) {
            if (tileSpec.equals("wifi")) return new WifiTile(this);
            else if (tileSpec.equals("bt")) return new BluetoothTile(this);
            else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
            else if (tileSpec.equals("cell")) return new CellularTile(this);
            else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
            else if (tileSpec.equals("dnd")) return new DndTile(this);
            else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
            else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
            else if (tileSpec.equals("location")) return new LocationTile(this);
            else if (tileSpec.equals("cast")) return new CastTile(this);
            else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
            else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
        }
    
    

    可以看到这里具体创建了QSTitle的各个对象。
    那么这些QSTitle对象又是如何加载到QSPanel的View中呢?
    而QSPanel在哪加入到了StatusBarHeaderView中。
    回头在看看PhoneStatusBar的makeStatusBarView方法:

    // Set up the quick settings tile panel
            mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
            if (mQSPanel != null) {
                final QSTileHost qsh = new QSTileHost(mContext, this,
                        mBluetoothController, mLocationController, mRotationLockController,
                        mNetworkController, mZenModeController, mHotspotController,
                        mCastController, mFlashlightController,
                        mUserSwitcherController, mKeyguardMonitor,
                        mSecurityController,
                        mAudioProfileController
                        );
                mQSPanel.setHost(qsh);
                mQSPanel.setTiles(qsh.getTiles());   
                mHeader.setQSPanel(mQSPanel);//mHeader->StatusBarHeaderView QSPanel加入到了StatusBarHeaderView中。
                qsh.setCallback(new QSTileHost.Callback() {
                    @Override
                    public void onTilesChanged() {
                        mQSPanel.setTiles(qsh.getTiles());
                    }
                });
            }
    

    刚才我们从QSTileHost的构造函数开始,分析了具体每个QSTitle的实例化。我们现在创建QSTileHost之后,又发生了什么。

    mQSPanel.setHost(qsh);//将QSTileHost对象放入QSPanel
    mQSPanel.setTiles(qsh.getTiles());
    /*QSTileHost获得title用来设置QSPanel的title,从函数名来看,
    很像是我们上面问题的答案
    */
    

    看看qsh.getTiles()及mQSPanel.setTiles()

        @Override
        public Collection<QSTile<?>> getTiles() {  
            return mTiles.values();//获得title值
        }
        
        
        public void setTiles(Collection<QSTile<?>> tiles) {
            for (TileRecord record : mRecords) {
                removeView(record.tileView);
            }
            mRecords.clear();
            for (QSTile<?> tile : tiles) {
                addTile(tile);//在这里,具体的每个QStitle在这里被addTile进了QSPanel
            }
            if (isShowingDetail()) {
                mDetail.bringToFront();
            }
        }
    
    

    看看addTile():

    private void addTile(final QSTile<?> tile) {
            final TileRecord r = new TileRecord();
            r.tile = tile;
            r.tileView = tile.createTileView(mContext);
            r.tileView.setVisibility(View.GONE);
            final QSTile.Callback callback = new QSTile.Callback() {
                @Override
                public void onStateChanged(QSTile.State state) {
                    if (!r.openingDetail) {
                        drawTile(r, state);
                    }
                }
                @Override
                public void onShowDetail(boolean show) {
                    QSPanel.this.showDetail(show, r);
                }
                @Override
                public void onToggleStateChanged(boolean state) {
                    if (mDetailRecord == r) {
                        fireToggleStateChanged(state);
                    }
                }
                @Override
                public void onScanStateChanged(boolean state) {
                    r.scanState = state;
                    if (mDetailRecord == r) {
                        fireScanStateChanged(r.scanState);
                    }
                }
    
                @Override
                public void onAnnouncementRequested(CharSequence announcement) {
                    announceForAccessibility(announcement);
                }
            };
            r.tile.setCallback(callback);
            final View.OnClickListener click = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    r.tile.click();
                }
            };
            final View.OnClickListener clickSecondary = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    r.tile.secondaryClick();
                }
            };
            final View.OnLongClickListener longClick = new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    r.tile.longClick();
                    return true;
                }
            };
            r.tileView.init(click, clickSecondary, longClick);
            r.tile.setListening(mListening);
            callback.onStateChanged(r.tile.getState());
            r.tile.refreshState();
            mRecords.add(r);
    
            addView(r.tileView);//加载进QSPanel
        }
    

    addTile()中创建了一个callback,实际运行中Title刷新,点击事件等许多操作都将与这个callback挂钩
    同时,最后addView函数也将这个QSTitle加载进了QSPanel中。
    至此,文章告一段落。

    参考文章:
    Android SystemServer 启动流程
    Android之SystemUI加载流程和NavigationBar的分析
    http://www.2cto.com/kf/201604/499625.html
    Android 6.0 系统学习之 Zygote
    http://www.open-open.com/lib/view/open1449567150379.html

    相关文章

      网友评论

          本文标题:QSTitle创建流程

          本文链接:https://www.haomeiwen.com/subject/vwikettx.html