1. 程式人生 > >SystemUI原始碼分析四(QSPanel顯示的流程)

SystemUI原始碼分析四(QSPanel顯示的流程)

quick settings是statusbar的一部分,隨著statusbarview的建立而載入,上一篇SystemUI原始碼分析三中已經分析了statusbar的載入流程,那麼這裡將繼續對其中的quick settings部分進行簡單的分析,弄清楚它的載入顯示流程。首先從PhoneStausBar.java中開始分析。

protected PhoneStatusBarView makeStatusBarView() {
        final Context context = mContext;

    // 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); mQSPanel.setHost(qsh); mQSPanel.setTiles(qsh.getTiles()); mBrightnessMirrorController = new
BrightnessMirrorController(mStatusBarWindow); mQSPanel.setBrightnessMirror(mBrightnessMirrorController); mHeader.setQSPanel(mQSPanel); qsh.setCallback(new QSTileHost.Callback() { @Override public void onTilesChanged() { mQSPanel.setTiles(qsh.getTiles()); } }); } }

1、獲得QSPanel這個viewgroup,然後建立QSTileHost物件,通過呼叫QSPanel的setHost()函式將QSTileHost物件傳遞給QSPanel.java.

QSTileHost的構造方法分析

protected static final String TILES_SETTING = "sysui_qs_tiles";

public QSTileHost(Context context, PhoneStatusBar statusBar,
        BluetoothController bluetooth, LocationController location,
        RotationLockController rotation, NetworkController network,
        ZenModeController zen, HotspotController hotspot,
        CastController cast, FlashlightController flashlight,
        UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
        SecurityController security) {
    mContext = context;
    mStatusBar = statusBar;
    mBluetooth = bluetooth;
    mLocation = location;
    mRotation = rotation;
    mNetwork = network;
    mZen = zen;
    mHotspot = hotspot;
    mCast = cast;
    mFlashlight = flashlight;
    mUserSwitcherController = userSwitcher;
    mKeyguard = keyguard;
    mSecurity = security;

    final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
            Process.THREAD_PRIORITY_BACKGROUND);
    ht.start();
    mLooper = ht.getLooper();

    TunerService.get(mContext).addTunable(this, TILES_SETTING);
}

呼叫TunerService.get(mContext).addTunable()函式查詢TILES_SETTING

TunerService.java

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);
    tunable.onTuningChanged(key, value);
}

tunable.onTuningChanged(key, value);查詢到的結果通過這個回撥方法返回

QSTileHost.java

@Override
public void onTuningChanged(String key, String newValue) {
    if (!TILES_SETTING.equals(key)) {
        return;
    }
    if (DEBUG) Log.d(TAG, "Recreating tiles");
    final List<String> tileSpecs = loadTileSpecs(newValue);
    if (tileSpecs.equals(mTileSpecs)) return;
    for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
        if (!tileSpecs.contains(tile.getKey())) {
            if (DEBUG) Log.d(TAG, "Destroying tile: " + 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));
            } catch (Throwable t) {
                Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
            }
        }
    }
    mTileSpecs.clear();
    mTileSpecs.addAll(tileSpecs);
    mTiles.clear();
    mTiles.putAll(newTiles);
    if (mCallback != null) {
        mCallback.onTilesChanged();
    }
}

這個函式主要做的是:

1.1、loadTileSpecs(newValue);//載入預設的tileSpecs。

protected List<String> loadTileSpecs(String tileList) {
    final Resources res = mContext.getResources();
    String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
    if (!TelephonyManager.isDeviceSupportLte()) {
        defaultTileList = defaultTileList.replace(",lte", "");
    }
    if (tileList == null) {
        tileList = res.getString(R.string.quick_settings_tiles);
        if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);
    } else {
        if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
    }
    final ArrayList<String> tiles = new ArrayList<String>();
    boolean addedDefault = false;
    for (String tile : tileList.split(",")) {
        tile = tile.trim();
        if (tile.isEmpty()) continue;
        if (tile.equals("default")) {
            if (!addedDefault) {
                tiles.addAll(Arrays.asList(defaultTileList.split(",")));
                addedDefault = true;
            }
        } else {
            tiles.add(tile);
        }
    }
    return tiles;
}

1.2、for循壞遍歷tileSpecs集合,把資訊儲存在newTiles這個map集合中,最後全部儲存在mTiles集合。

1.3、newTiles.put(tileSpec, createTile(tileSpec));建立快捷設定tile的物件。

protected QSTile<?> createTile(String tileSpec) {
    if (tileSpec.equals("wifi") && !WCN_DISABLED) return new WifiTile(this);
    else if (tileSpec.equals("bt") && !WCN_DISABLED) 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("data")) return new DataConnectionTile(this);
    else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
    else if (tileSpec.equals("lte") && TelephonyManager.isDeviceSupportLte()
            && SystemUIPluginsHelper.getInstance().show4GInQS())
            return new LteServiceTile(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") && !WCN_DISABLED) return new LocationTile(this);
    else if (tileSpec.equals("cast") && !WCN_DISABLED && mContext.getResources().getBoolean(
            com.android.internal.R.bool.config_enableWifiDisplay)) return new CastTile(this);
    else if (tileSpec.equals("audioprofile")) return new AudioProfileTile(this);
    else if (tileSpec.equals("hotspot") && !WCN_DISABLED) return new HotspotTile(this);
    else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
    else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}

1.4、mCallback.onTilesChanged();//回撥onTilesChanged()函式,通知PhoneStatus.java對快捷設定項顯示更新。

那在回到PhoneStatusBar.java中的makeStatusBarView()函式中分析。

2、mQSPanel.setTiles(qsh.getTiles());在上面我們提到載入的快捷設定tiles都儲存在了mTiles集合中。QSTileHost.java中提供了getTiles()方法取得mTiles集合。

QSPanel.java

public void setTiles(Collection<QSTile<?>> tiles) {
    for (TileRecord record : mRecords) {
        removeView(record.tileView);
    }
    mRecords.clear();
    for (QSTile<?> tile : tiles) {
        addTile(tile);
    }
    if (isShowingDetail()) {
        mDetail.bringToFront();
    }
}

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) {
   if(sSupportBtWifiSoftApCoexist.equals("false")){
                if(v.getId() == BLUETOOTH_VIEW_ID){
                    mTimeStart = System.currentTimeMillis();
                }
                if(v.getId() == HOTSPOT_VIEW_ID && (System.currentTimeMillis() - mTimeStart) < 500){
                    return;
                }
                if(v.getId() == AIRPLANE_VIEW_ID){
                    mAirTimeStart = System.currentTimeMillis();
                }
                if(v.getId() == HOTSPOT_VIEW_ID && (System.currentTimeMillis() - mAirTimeStart) < 800){
                    return;
                }
            }
            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.java中的addTile()方法最終呼叫了addView()方法將tile新增到QSPanel這個viewgroup中。在新增進去前先對它初始化。

3、mQSPanel.setBrightnessMirror(mBrightnessMirrorController);

4、qsh.setCallback();//註冊Tiles發生改變時回撥onTiles。

那麼quick settings tile panel的載入就分析到這裡了。