最近看了一个wifi, ethernet切换,状态栏图表显示的问题。记录一下追踪由于网络状态变化,SystemUI 状态栏网络图标显示的流程。

先看一下SystemUI这边:

/frameworks/base/services/java/com/android/server/SystemServer.java

/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {......
......
2236        // We now tell the activity manager it is okay to run third party
2237        // code.  It will call back into us once it has gotten to the state
2238        // where third party code can really run (but before it has actually
2239        // started launching the initial applications), for us to complete our
2240        // initialization.
2241        mActivityManagerService.systemReady(() -> {......
......2276            t.traceBegin("StartSystemUI");
2277            try {
2278                startSystemUi(context, windowManagerF);
2279            } catch (Throwable e) {
2280                reportWtf("starting System UI", e);
2281            }
2282            t.traceEnd();......
......
}private static void startSystemUi(Context context, WindowManagerService windowManager) {
2534        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
2535        Intent intent = new Intent();
2536        intent.setComponent(pm.getSystemUiServiceComponent());
2537        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
2538        //Slog.d(TAG, "Starting service: " + intent);
2539        context.startServiceAsUser(intent, UserHandle.SYSTEM);
2540        windowManager.onSystemUiStarted();
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

public SystemUIService(
50            @Main Handler mainHandler,
51            DumpHandler dumpHandler,
52            BroadcastDispatcher broadcastDispatcher,
53            LogBufferFreezer logBufferFreezer) {
54        super();
55        mMainHandler = mainHandler;
56        mDumpHandler = dumpHandler;
57        mBroadcastDispatcher = broadcastDispatcher;
58        mLogBufferFreezer = logBufferFreezer;
59    }
60
61    @Override
62    public void onCreate() {
63        super.onCreate();
64
65        // Start all of SystemUI
66        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
67
68        // Finish initializing dump logic
69        mLogBufferFreezer.attach(mBroadcastDispatcher);
70
71        // For debugging RescueParty
72        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
73            throw new RuntimeException();
74        }
75
76        if (Build.IS_DEBUGGABLE) {
77            // b/71353150 - looking for leaked binder proxies
78            BinderInternal.nSetBinderProxyCountEnabled(true);
79            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
80            BinderInternal.setBinderProxyCountCallback(
81                    new BinderInternal.BinderProxyLimitListener() {
82                        @Override
83                        public void onLimitReached(int uid) {
84                            Slog.w(SystemUIApplication.TAG,
85                                    "uid " + uid + " sent too many Binder proxies to uid "
86                                    + Process.myUid());
87                        }
88                    }, mMainHandler);
89        }
90
91        // Bind the dump service so we can dump extra info during a bug report
92        startServiceAsUser(
93                new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
94                UserHandle.SYSTEM);
}/**
* Makes sure that all the SystemUI services are running. If they are already running, this is a
* no-op. This is needed to conditinally start all the services, as we only need to have it in
* the main process.
* <p>This method must only be called from the main thread.</p>
*/public void startServicesIfNeeded() {
142        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
143        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}

SystemUI 要启动的所有服务都是在数组 config_systemUIServiceComponents中定义

127    /** Returns the list of system UI components that should be started. */
128    public String[] getSystemUIServiceComponents(Resources resources) {
129        return resources.getStringArray(R.array.config_systemUIServiceComponents);
130    }/frameworks/base/packages/SystemUI/res/values/config.xml
302    <!-- SystemUI Services: The classes of the stuff to start. -->
303    <string-array name="config_systemUIServiceComponents" translatable="false">
304        <item>com.android.systemui.util.NotificationChannels</item>
305        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
306        <item>com.android.systemui.recents.Recents</item>
307        <item>com.android.systemui.volume.VolumeUI</item>
308        <item>com.android.systemui.stackdivider.Divider</item>
309        <item>com.android.systemui.statusbar.phone.StatusBar</item>
310        <item>com.android.systemui.usb.StorageNotification</item>
311        <item>com.android.systemui.power.PowerUI</item>
312        <item>com.android.systemui.media.RingtonePlayer</item>
313        <item>com.android.systemui.keyboard.KeyboardUI</item>
314        <item>com.android.systemui.pip.PipUI</item>
315        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
316        <item>@string/config_systemUIVendorServiceComponent</item>
317        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
318        <item>com.android.systemui.LatencyTester</item>
319        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
320        <item>com.android.systemui.ScreenDecorations</item>
321        <item>com.android.systemui.biometrics.AuthController</item>
322        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
323        <item>com.android.systemui.SizeCompatModeActivityController</item>
324        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
325        <item>com.android.systemui.theme.ThemeOverlayController</item>
326        <item>com.android.systemui.accessibility.WindowMagnification</item>
327        <item>com.android.systemui.accessibility.SystemActions</item>
328        <item>com.android.systemui.toast.ToastUI</item>
329    </string-array>
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
159        if (mServicesStarted) {
160            return;
161        }
162        mServices = new SystemUI[services.length];
163
164        if (!mBootCompleteCache.isBootComplete()) {
165            // check to see if maybe it was already completed long before we began
166            // see ActivityManagerService.finishBooting()
167            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
168                mBootCompleteCache.setBootComplete();
169                if (DEBUG) {
170                    Log.v(TAG, "BOOT_COMPLETED was already sent");
171                }
172            }
173        }
174
175        final DumpManager dumpManager = mRootComponent.createDumpManager();
176
177        Log.v(TAG, "Starting SystemUI services for user " +
178                Process.myUserHandle().getIdentifier() + ".");
179        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
180                Trace.TRACE_TAG_APP);
181        log.traceBegin(metricsPrefix);
182        final int N = services.length;
183        for (int i = 0; i < N; i++) {
184            String clsName = services[i];
185            if (DEBUG) Log.d(TAG, "loading: " + clsName);
186            log.traceBegin(metricsPrefix + clsName);
187            long ti = System.currentTimeMillis();
188            try {
189                SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
190                if (obj == null) {
191                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
192                    obj = (SystemUI) constructor.newInstance(this);
193                }
194                mServices[i] = obj;
195            } catch (ClassNotFoundException
196                    | NoSuchMethodException
197                    | IllegalAccessException
198                    | InstantiationException
199                    | InvocationTargetException ex) {
200                throw new RuntimeException(ex);
201            }
202
203            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
204            mServices[i].start();
205            log.traceEnd();
206
207            // Warn if initialization of component takes too long
208            ti = System.currentTimeMillis() - ti;
209            if (ti > 1000) {
210                Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
211            }
212            if (mBootCompleteCache.isBootComplete()) {
213                mServices[i].onBootCompleted();
214            }
215
216            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
217        }
218        mRootComponent.getInitController().executePostInitTasks();
219        log.traceEnd();
220
221        mServicesStarted = true;
}

SystemBars 这个 SystemUI服务是整个System视图创建的入口类,它被启动时会调用 start() 方法,这个方法中通过下面方法创建整个SystemUI视图并添加到WindowsManager中。

createAndAddWindows(result);public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {// 创建整个SystemUI视图
2631        makeStatusBarView(result);// 把视图添加到Window中
2632        mNotificationShadeWindowController.attach();
2633        mStatusBarWindowController.attach();
}

关于SystemUI service和StatusBar创建,可以参考下面几个文章分析:

https://juejin.cn/post/6844904135557382158

https://juejin.cn/post/6844904135720960014

https://www.jianshu.com/p/c7098671682e

SystemUI中StatusBar的图标控制器实现类为StatusBarIconControllerImpl,其继承了StatusBarIconController的接口,用于跟踪所有图标的状态,并将对应的状态发送给注册的图标管理器(IconManagers)。当我们在StatusBar中获取到它的实例后,还会将它传给PhoneStatusBarPolicy和StatusBarSignalPolicy对象。PhoneStatusBarPolicy控制启动时装载哪些图标(蓝牙,定位等),而StatusBarSignalPolicy控制网络信号图标(移动网络,WiFi,以太网)的变化。

StatusBarSignalPolicy实现了NetworkControllerImpl.SignalCallback接口,SignalCallback接口定义在NetworkControllerImpl实现的接口NetworkController中。

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java

注册广播监听:

    @VisibleForTesting
void registerListeners() {
334        for (int i = 0; i < mMobileSignalControllers.size(); i++) {
335            MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
336            mobileSignalController.registerListener();
337        }
338        if (mSubscriptionListener == null) {
339            mSubscriptionListener = new SubListener();
340        }
341        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
342        mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
343
344        // broadcasts
345        IntentFilter filter = new IntentFilter();
346        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
347        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
348        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
349        filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
350        filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
351        filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
352        filter.addAction(Intent.ACTION_SERVICE_STATE);
353        filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
354        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
355        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
356        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
357        filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
358        mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
359        mListening = true;
360
361        // Initial setup of connectivity. Handled as if we had received a sticky broadcast of
362        // ConnectivityManager.CONNECTIVITY_ACTION or ConnectivityManager.INET_CONDITION_ACTION.
363        mReceiverHandler.post(this::updateConnectivity);
364
365        // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast
366        // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION
367        mReceiverHandler.post(mWifiSignalController::fetchInitialState);
368
369        // Initial setup of mLastServiceState. Only run if there is no service state yet.
370        // Each MobileSignalController will also get their corresponding
371        mReceiverHandler.post(() -> {
372            if (mLastServiceState == null) {
373                mLastServiceState = mPhone.getServiceState();
374                if (mMobileSignalControllers.size() == 0) {
375                    recalculateEmergency();
376                }
377            }
378        });
379
380        updateMobileControllers();
381
382        // Initial setup of emergency information. Handled as if we had received a sticky broadcast
383        // of TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED.
384        mReceiverHandler.post(this::recalculateEmergency);
}

处理广播:

public void onReceive(Context context, Intent intent) {
560        if (CHATTY) {
561            Log.d(TAG, "onReceive: intent=" + intent);
562        }
563        final String action = intent.getAction();
564        switch (action) {
565            case ConnectivityManager.CONNECTIVITY_ACTION:
566            case ConnectivityManager.INET_CONDITION_ACTION:
567                updateConnectivity();
568                break;
569            case Intent.ACTION_AIRPLANE_MODE_CHANGED:
570                refreshLocale();
571                updateAirplaneMode(false);
572                break;
573            case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
574                // We are using different subs now, we might be able to make calls.
575                recalculateEmergency();
576                break;
577            case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
578                // Notify every MobileSignalController so they can know whether they are the
579                // data sim or not.
580                for (int i = 0; i < mMobileSignalControllers.size(); i++) {
581                    MobileSignalController controller = mMobileSignalControllers.valueAt(i);
582                    controller.handleBroadcast(intent);
583                }
584                mConfig = Config.readConfig(mContext);
585                mReceiverHandler.post(this::handleConfigurationChanged);
586                break;
587            case Intent.ACTION_SIM_STATE_CHANGED:
588                // Avoid rebroadcast because SysUI is direct boot aware.
589                if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
590                    break;
591                }
592                // Might have different subscriptions now.
593                updateMobileControllers();
594                break;
595            case Intent.ACTION_SERVICE_STATE:
596                mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
597                if (mMobileSignalControllers.size() == 0) {
598                    // If none of the subscriptions are active, we might need to recalculate
599                    // emergency state.
600                    recalculateEmergency();
601                }
602                break;
603            case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
604                mConfig = Config.readConfig(mContext);
605                mReceiverHandler.post(this::handleConfigurationChanged);
606                break;
607            default:
608                int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
609                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
610                if (SubscriptionManager.isValidSubscriptionId(subId)) {
611                    if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
612                        mMobileSignalControllers.get(subId).handleBroadcast(intent);
613                    } else {
614                        // Can't find this subscription...  We must be out of date.
615                        updateMobileControllers();
616                    }
617                } else {//wifi状态图标处理
618                    // No sub id, must be for the wifi.
619                    mWifiSignalController.handleBroadcast(intent);
620                }
621                break;
622        }
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java

119    /**
120     * Extract wifi state directly from broadcasts about changes in wifi state.
121     */
public void handleBroadcast(Intent intent) {
123        mWifiTracker.handleBroadcast(intent);
124        mCurrentState.enabled = mWifiTracker.enabled;
125        mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
126        mCurrentState.connected = mWifiTracker.connected;
127        mCurrentState.ssid = mWifiTracker.ssid;
128        mCurrentState.rssi = mWifiTracker.rssi;
129        mCurrentState.level = mWifiTracker.level;
130        mCurrentState.statusLabel = mWifiTracker.statusLabel;
131        notifyListenersIfNecessary();
}

/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java

public void handleBroadcast(Intent intent) {
167        if (mWifiManager == null) {
168            return;
169        }
170        String action = intent.getAction();
171        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
172            updateWifiState();
173        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
174            updateWifiState();
175            final NetworkInfo networkInfo =
176                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
177            connected = networkInfo != null && networkInfo.isConnected();
178            mWifiInfo = null;
179            ssid = null;
180            if (connected) {
181                mWifiInfo = mWifiManager.getConnectionInfo();
182                if (mWifiInfo != null) {
183                    if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
184                        ssid = mWifiInfo.getPasspointProviderFriendlyName();
185                    } else {
186                        ssid = getValidSsid(mWifiInfo);
187                    }
188                    updateRssi(mWifiInfo.getRssi());
189                    maybeRequestNetworkScore();
190                }
191            }
192            updateStatusLabel();
193            mCallback.run();
194        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
195            // Default to -200 as its below WifiManager.MIN_RSSI.
196            updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
197            updateStatusLabel();
198            mCallback.run();
199        }
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java

public void notifyListenersIfNecessary() {
161        if (isDirty()) {
162            saveLastState();
163            notifyListeners();
164        }
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java

80    @Override
81    public void notifyListeners(SignalCallback callback) {
82        // only show wifi in the cluster if connected or if wifi-only
83        boolean visibleWhenEnabled = mContext.getResources().getBoolean(
84                R.bool.config_showWifiIndicatorWhenEnabled);
85        boolean wifiVisible = mCurrentState.enabled && (
86                (mCurrentState.connected && mCurrentState.inetCondition == 1)
87                        || !mHasMobileDataFeature || mCurrentState.isDefault
88                        || visibleWhenEnabled);
89        String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null;
90        boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
91        String contentDescription = getTextIfExists(getContentDescription()).toString();
92        if (mCurrentState.inetCondition == 0) {
93            contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
94        }
95        IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
96        IconState qsIcon = new IconState(mCurrentState.connected,
97                mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
98                        : getQsCurrentIconId(), contentDescription);
99        callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
100                ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
101                wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
102    }

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java

@Override
public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
140            boolean activityIn, boolean activityOut, String description, boolean isTransient,
141            String statusLabel) {
142
143        boolean visible = statusIcon.visible && !mBlockWifi;
144        boolean in = activityIn && mActivityEnabled && visible;
145        boolean out = activityOut && mActivityEnabled && visible;
146
147        WifiIconState newState = mWifiIconState.copy();
148
149        newState.visible = visible;
150        newState.resId = statusIcon.icon;
151        newState.activityIn = in;
152        newState.activityOut = out;
153        newState.slot = mSlotWifi;
154        newState.airplaneSpacerVisible = mIsAirplaneMode;
155        newState.contentDescription = statusIcon.contentDescription;
156
157        MobileIconState first = getFirstMobileState();
158        newState.signalSpacerVisible = first != null && first.typeId != 0;
159
160        updateWifiIconWithState(newState);
161        mWifiIconState = newState;
}private void updateWifiIconWithState(WifiIconState state) {
170        if (state.visible && state.resId > 0) {
171            mIconController.setSignalIcon(mSlotWifi, state);
172            mIconController.setIconVisibility(mSlotWifi, true);
173        } else {
174            mIconController.setIconVisibility(mSlotWifi, false);
175        }
}

通过StatusBarIconController接口设置图标的套路都是一样的

  1. 获取图标名字
  2. 监听事件
  3. 通过StatusBarIconController相应的方法设置图标。

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java

public void onSetSignalIcon(int viewIndex, WifiIconState state) {
377            StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
378            if (wifiView != null) {
379                wifiView.applyWifiState(state);
380            }
381
382            if (mIsInDemoMode) {
383                mDemoStatusIcons.updateWifiState(state);
384            }
}

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java

public void applyWifiState(WifiIconState state) {
178        boolean requestLayout = false;
179
180        if (state == null) {
181            requestLayout = getVisibility() != View.GONE;
182            setVisibility(View.GONE);
183            mState = null;
184        } else if (mState == null) {
185            requestLayout = true;
186            mState = state.copy();
187            initViewState();
188        } else if (!mState.equals(state)) {
189            requestLayout = updateState(state.copy());
190        }
191
192        if (requestLayout) {
193            requestLayout();
194        }
}private boolean updateState(WifiIconState state) {
198        setContentDescription(state.contentDescription);
199        if (mState.resId != state.resId && state.resId >= 0) {
200            mWifiIcon.setImageDrawable(mContext.getDrawable(state.resId));
201        }
202
203        mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
204        mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
205        mInoutContainer.setVisibility(
206                (state.activityIn || state.activityOut) ? View.VISIBLE : View.GONE);
207        mAirplaneSpacer.setVisibility(state.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
208        mSignalSpacer.setVisibility(state.signalSpacerVisible ? View.VISIBLE : View.GONE);
209
210        boolean needsLayout = state.activityIn != mState.activityIn
211                ||state.activityOut != mState.activityOut;
212
213        if (mState.visible != state.visible) {
214            needsLayout |= true;
215            setVisibility(state.visible ? View.VISIBLE : View.GONE);
216        }
217
218        mState = state;
219        return needsLayout;
}

借用https://www.jianshu.com/p/c7098671682e文章里的图来再看下流程(图中是mobile signal和图标的更新流程)。

Android SystemUI 状态栏网络图标显示分析(Android 11)相关推荐

  1. Android10 SystemUI状态栏网络图标流程分析

    Android 10 SystemUI网络图标刷新与显示 涉及文件目录: android/frameworks/base/packages/SystemUI/src/com/android/syste ...

  2. android 在状态栏耳机图标显示图标显示图标显示图标,Android 通知栏图标

    先来一段发送普通通知的代码. NotificationManager notificationManager = (NotificationManager) getActivity().getSyst ...

  3. Android 12 悬浮通知/横幅通知状态栏应用图标显示不全

    先看下问题的表现情况吧 这个模块的实现在SystemUI 这里先列举下与这个模块以及本文要描述的相关代码和资源文件,后面逐个分析 SystemUI/src/com/android/systemui/s ...

  4. Android 10 状态栏通知图标和下拉状态栏图标为白色问题

    前言 安装第三方应用,会在状态栏上面和下拉状态栏通知图标显示白色 原因 因为google在android5.0上面做了限制,为了统一系统风格.之后的状态栏icon就不能够随便用一张色彩丰富的图片了,只 ...

  5. java手机状态栏圆形图标,android实现状态栏添加图标的函数实例

    本文实例讲述了android实现状态栏添加图标的函数.分享给大家供大家参考.具体如下: private void showNotification() { // 创建一个NotificationMan ...

  6. android显示通知图标大全,Android应用开发之android 桌面APP应用图标显示通知消息的数量显示与去除...

    本文将带你了解Android应用开发之android 桌面APP应用图标显示通知消息的数量显示与去除,希望本文对大家学Android有所帮助. android   桌面APP应用图标显示通知消息的数量 ...

  7. 基本系统设备感叹号_win7系统网络图标显示感叹号的问题

    有系统之家的小伙伴,在使用win764位纯净版系统上网的时候,出现网络图标显示感叹号的问题.这种问题我们可以通过在网络检测修复中进行自行检测.或者是检查一下是不是硬件设备的问题.详细解决步骤就来看下系 ...

  8. win7计算机未连接网络连接,解决win7能上网但是网络图标显示未连接的方法-win7之家...

    现在使用电脑上网的人越来越多了,当然在上网的过程中也会遇到各种各样的问题,比如最近就有不少用户发现电脑在开机的时候连接了网络,可是却发现也能够正常上网,但是任务栏右下角的网络图标却不知道何时变成了显示 ...

  9. 解决win7能上网却右下角网络图标显示红色叉号的问题

    解决win7能上网却右下角网络图标显示红色叉号的问题 参考文章: (1)解决win7能上网却右下角网络图标显示红色叉号的问题 (2)https://www.cnblogs.com/william-le ...

最新文章

  1. mysql 函数,关键字,特性
  2. 计算机教学中因才施教,浅析高校《大学计算机基础》教学中的因材施教
  3. 捕捉到了异常继续循环_前端异常处理最佳实践
  4. java常见笔试_Java 常见笔试题(2)
  5. C#与halcon联合开发——内存溢出
  6. 织梦charset.func.php,DEDECMS织梦程序实现熊掌号API提交接口推送(PHP推送)
  7. 负载均衡—nginx实现waf
  8. SQLyog客户端 导入sql文件乱码的解决方法
  9. 腾讯视频 android 2倍,腾讯视频多倍速播放产品设计小结
  10. 十分钟理解线性代数的本质_如何理解线性代数?
  11. 天空卫士API数据安全解决方案
  12. Lrc文件与音乐的同步显示
  13. 计算机禁用网络后怎么打开,无线网关,教您笔记本无线网络禁用后怎么开启
  14. Ecshop3.x漏洞复现
  15. 如何用计算机弹出斗地主的声音,玩斗地主没声音电脑瞎出牌。我点的没有.怎么办?...
  16. 研究生图像处理该怎的自学_我的研究生这三年
  17. 2021-12-29 神经网络
  18. 2026年中国软件定义存储市场容量将接近45.1亿美元
  19. 25 匹马 5 条赛道,最快需要几轮求出前 3 名?
  20. android 4.4 电池电量管理底层分析(C\C++层)

热门文章

  1. RS485信号的测量
  2. 如何在百度中脱颖而出——前端与SEO
  3. 深度linux安装virtualbox,Deepin 20 安装 VirtualBox 6.1
  4. Trimble Data Conversion编程相关补充
  5. VB通过以太网接口使用winsock的永宏PLC上位机通讯系统设计
  6. 互联网早报:字节跳动推出“飞书文档”独立App.....
  7. Midas GTS NX 模型转为(导入、转换) FLAC3D5.0的模型 c++源码 (midas to flac3d)
  8. 全国计算机考试的准考证号查询
  9. 复合材料 matlab,基于Matlab的复合材料刚度分析.pdf
  10. mysql必须包含数据组_MySQL必知必会--分 组 数 据