Android14 QS编辑页面面板的加载解析

发布于:2025-08-13 ⋅ 阅读:(18) ⋅ 点赞:(0)

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java

点击编辑按钮

mEditButton.setOnClickListener(view -> {
            if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
                return;
            }
            mActivityStarter
                    .postQSRunnableDismissingKeyguard(() -> mQsPanelController.showEdit(view));
        });

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java

QsCustomizerController开始显示

    /** Start customizing the Quick Settings. */
    public void showEdit(View view) {
        view.post(() -> {
            if (!mQsCustomizerController.isCustomizing()) {
                int[] loc = view.getLocationOnScreen();
                int x = loc[0] + view.getWidth() / 2;
                int y = loc[1] + view.getHeight() / 2;
                mQsCustomizerController.show(x, y, false);
            }
        });
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java

视图开始显示,mView是指QSCustomizer这个视图

    @Inject
    protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
            QSHost qsHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
            KeyguardStateController keyguardStateController, LightBarController lightBarController,
            ConfigurationController configurationController, UiEventLogger uiEventLogger) {
        super(view);
        mTileQueryHelper = tileQueryHelper;
        mQsHost = qsHost;
        mTileAdapter = tileAdapter;
        mScreenLifecycle = screenLifecycle;
        mKeyguardStateController = keyguardStateController;
        mLightBarController = lightBarController;
        mConfigurationController = configurationController;
        mUiEventLogger = uiEventLogger;

        mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
    }

    @Override
    protected void onViewAttached() {
        mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);

        mConfigurationController.addCallback(mConfigurationListener);
		//把mTileAdapter这个注册到mTileQueryHelper中,好方便加载完数据进行回调刷新view
        mTileQueryHelper.setListener(mTileAdapter);
        ......
	}

    public void show(int x, int y, boolean immediate) {
        if (!mView.isShown()) {
            setTileSpecs();
            if (immediate) {
                mView.showImmediately();
            } else {
                mView.show(x, y, mTileAdapter);
                mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
            }
            mTileQueryHelper.queryTiles(mQsHost);
            mKeyguardStateController.addCallback(mKeyguardCallback);
            mView.updateNavColors(mLightBarController);
        }
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

开始加载数据

    public void queryTiles(QSHost host) {
        mTiles.clear();
        mSpecs.clear();
        mFinished = false;
        // Enqueue jobs to fetch every system tile and then ever package tile.
        addCurrentAndStockTiles(host);
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

主要是R.string.quick_settings_tiles_stock,加载编辑面板中的Stock数据

private void addCurrentAndStockTiles(QSHost host) {
        String stock = mContext.getString(R.string.quick_settings_tiles_stock);
        String current = Settings.Secure.getString(mContext.getContentResolver(),
                Settings.Secure.QS_TILES);
        final ArrayList<String> possibleTiles = new ArrayList<>();
        if (current != null) {
            // The setting QS_TILES is not populated immediately upon Factory Reset
            possibleTiles.addAll(Arrays.asList(current.split(",")));
        } else {
            current = "";
        }
        String[] stockSplit =  stock.split(",");
        for (String spec : stockSplit) {
            if (!current.contains(spec)) {
                possibleTiles.add(spec);
            }
        }
        if (Build.IS_DEBUGGABLE && !current.contains(GarbageMonitor.MemoryTile.TILE_SPEC)) {
            possibleTiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
        }

        final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
        possibleTiles.remove("cell");
        possibleTiles.remove("wifi");

        for (String spec : possibleTiles) {
            // Only add current and stock tiles that can be created from QSFactoryImpl.
            // Do not include CustomTile. Those will be created by `addPackageTiles`.
            if (spec.startsWith(CustomTile.PREFIX)) continue;
            final QSTile tile = host.createTile(spec);
            if (tile == null) {
                continue;
            } else if (!tile.isAvailable()) {
                tile.setTileSpec(spec);
                tile.destroy();
                continue;
            }
            tile.setTileSpec(spec);
            tilesToAdd.add(tile);
        }

        new TileCollector(tilesToAdd, host).startListening();
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

实现监听QSTile的状态变化(观察者模式)

这里主要看这个地方:pair.mTile.refreshState()

  实现了QSTile.Callback回调
  private class TileCollector implements QSTile.Callback {

        private final List<TilePair> mQSTileList = new ArrayList<>();
        private final QSHost mQSHost;

        TileCollector(List<QSTile> tilesToAdd, QSHost host) {
            for (QSTile tile: tilesToAdd) {
            	//包装一下
                TilePair pair = new TilePair(tile);
                mQSTileList.add(pair);
            }
            mQSHost = host;
            if (tilesToAdd.isEmpty()) {
                mBgExecutor.execute(this::finished);
            }
        }

        private void finished() {
            notifyTilesChanged(false);
            addPackageTiles(mQSHost);
        }
		//注册每个Tile的Callback回调和Listening回调,使得TileCollector作为监听者加入观察每个Tile的改变
        private void startListening() {
            for (TilePair pair: mQSTileList) {
                pair.mTile.addCallback(this);
                pair.mTile.setListening(this, true);
                // Make sure that at least one refresh state happens
                pair.mTile.refreshState();
            }
        }

        // This is called in the Bg thread
        @Override
        public void onStateChanged(State s) {
            boolean allReady = true;
            for (TilePair pair: mQSTileList) {
                if (!pair.mReady && pair.mTile.isTileReady()) {
                    pair.mTile.removeCallback(this);
                    pair.mTile.setListening(this, false);
                    pair.mReady = true;
                } else if (!pair.mReady) {
                    allReady = false;
                }
            }
            if (allReady) {
                for (TilePair pair : mQSTileList) {
                    QSTile tile = pair.mTile;
                    final QSTile.State state = tile.getState().copy();
                    // Ignore the current state and get the generic label instead.
                    state.label = tile.getTileLabel();
                    tile.destroy();
                    addTile(tile.getTileSpec(), null, state, true);
                }
                finished();
            }
        }
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java

每个Tile进行刷新自己的状态

	//第二步:进行状态刷新回调
   @Override
     public void handleMessage(Message msg) {
         String name = null;
         try {
                ......
		          if (msg.what == REFRESH_STATE) {
			        name = "handleRefreshState";
			        handleRefreshState(msg.obj);
       		 }
      		 ......
     	}


	//第一步:发送Handler更新信息
    protected final void refreshState(@Nullable Object arg) {
        mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
    }


	//第三步:处理刷新逻辑
    protected final void handleRefreshState(@Nullable Object arg) {
        handleUpdateState(mTmpState, arg);
        boolean changed = mTmpState.copyTo(mState);
        if (mReadyState == READY_STATE_READYING) {
            mReadyState = READY_STATE_READY;
            changed = true;
        }
        if (changed) {
            mQSLogger.logTileUpdated(mTileSpec, mState);
            handleStateChanged();
        }
        mHandler.removeMessages(H.STALE);
        mHandler.sendEmptyMessageDelayed(H.STALE, getStaleTimeout());
        setListening(mStaleListener, false);
    }

	//第四步:这里触发状态改变回调
    private void handleStateChanged() {
        if (mCallbacks.size() != 0) {
            for (int i = 0; i < mCallbacks.size(); i++) {
                mCallbacks.get(i).onStateChanged(mState);
            }
        }
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

这里进行触发onStateChanged,遍历所有 tiles 都已就绪,如果已就绪,就添加到集合中进行存储,然后这时候就开始加载第三方的Tiles

// This is called in the Bg thread
@Override
public void onStateChanged(State s) {
    boolean allReady = true;  // 标记是否所有 tiles 都已就绪
    for (TilePair pair : mQSTileList) {  // 遍历所有待收集的 TilePair(包含 QSTile 和就绪状态)
        if (!pair.mReady && pair.mTile.isTileReady()) {  // 如果 tile 未标记就绪,且实际已就绪
            pair.mTile.removeCallback(this);  // 移除当前回调(避免重复监听)
            pair.mTile.setListening(this, false);  // 停止监听该 tile 的状态变化
            pair.mReady = true;  // 标记该 tile 为已就绪
        } else if (!pair.mReady) {  // 如果 tile 未就绪
            allReady = false;  // 则所有 tiles 未全部就绪
        }
    }
    if (allReady) {  // 当所有 tiles 都就绪后
        for (TilePair pair : mQSTileList) {  // 遍历所有就绪的 tiles
            QSTile tile = pair.mTile;
            final QSTile.State state = tile.getState().copy();  // 复制 tile 的当前状态(如图标、标签等)
            // Ignore the current state and get the generic label instead.
            state.label = tile.getTileLabel();  // 覆盖状态中的标签为 tile 的通用标签(忽略动态状态标签)
            tile.destroy();  // 销毁 tile 实例(释放资源,避免内存泄漏)
            addTile(tile.getTileSpec(), null, state, true);  // 将 tile 信息添加到全局列表(标记为系统 tile)
        }
        finished();  // 触发完成逻辑(通知监听器并继续处理第三方应用 tiles)
    }
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

addPackageTiles 这里是添加第三方的Tiles

        private void finished() {
            notifyTilesChanged(false); //这里还未将数据绑定到视图中
            addPackageTiles(mQSHost);
        }
    private void addPackageTiles(final QSHost host) {
        mBgExecutor.execute(() -> {
            Collection<QSTile> params = host.getTiles();
            PackageManager pm = mContext.getPackageManager();
            // 查询所有声明了 TileService.ACTION_QS_TILE 的服务(即第三方 QS tile 服务)
            List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                    new Intent(TileService.ACTION_QS_TILE), 0, mUserTracker.getUserId());
            String stockTiles = mContext.getString(R.string.quick_settings_tiles_stock);

            for (ResolveInfo info : services) {
                String packageName = info.serviceInfo.packageName;
                ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);

                // Don't include apps that are a part of the default tile set.
                // 跳过系统默认 tile(已在 stockTiles 中的 tile 不重复添加)
                if (stockTiles.contains(componentName.flattenToString())) {
                    continue;
                }

                final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
                String spec = CustomTile.toSpec(componentName);
                State state = getState(params, spec);
                if (state != null) {
                    addTile(spec, appLabel, state, false);
                    continue;
                }
                if (info.serviceInfo.icon == 0 && info.serviceInfo.applicationInfo.icon == 0) {
                    continue;
                }
                Drawable icon = info.serviceInfo.loadIcon(pm);
                if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
                    continue;
                }
                if (icon == null) {
                    continue;
                }
                icon.mutate();
                icon.setTint(mContext.getColor(android.R.color.white));
                CharSequence label = info.serviceInfo.loadLabel(pm);
                createStateAndAddTile(spec, icon, label != null ? label.toString() : "null",
                        appLabel);
            }
			notifyTilesChanged(true);  // 通知监听器:第三方 tile 加载完成,可更新 UI
        });
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java

这里开始将数据绑定到视图中,这个mListener是指mTileAdapter

    private void notifyTilesChanged(final boolean finished) {
        final ArrayList<TileInfo> tilesToReturn = new ArrayList<>(mTiles);
        mMainExecutor.execute(() -> {
            if (mListener != null) {
                mListener.onTilesChanged(tilesToReturn);
            }
            mFinished = finished;
        });
    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java

数据绑定进视图进行显示

 @Override
    public void onTilesChanged(List<TileInfo> tiles) {
        mAllTiles = tiles;
        recalcSpecs();
    }

    private void recalcSpecs() {
        if (mCurrentSpecs == null || mAllTiles == null) {
            return;
        }
        mOtherTiles = new ArrayList<TileInfo>(mAllTiles);
        mTiles.clear();
        mTiles.add(null);
        for (int i = 0; i < mCurrentSpecs.size(); i++) {
            final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i));
            if (tile != null) {
                mTiles.add(tile);
            }
        }
        mTiles.add(null);
        for (int i = 0; i < mOtherTiles.size(); i++) {
            final TileInfo tile = mOtherTiles.get(i);
            if (tile.isSystem) {
                mOtherTiles.remove(i--);
                mTiles.add(tile);
            }
        }
        mTileDividerIndex = mTiles.size();
        mTiles.add(null);
        mTiles.addAll(mOtherTiles);
        updateDividerLocations();
        notifyDataSetChanged();
    }

网站公告

今日签到

点亮在社区的每一天
去签到