SystemUI---RAT

Android9.0 SystemUI 屏蔽打开wifi时不显示4G图标的逻辑 Android 9.0 中打开wifi时,不显示4G图标,只有信号值,现项目需求在打开wifi时仍然显示4G图标。 排查及修改过程如下: systemui/src/com/android/systemui/statusbar/StatusBarMobileView.java private void updateState(MobileIconState state) { //省略部分代码 if (mState.typeId != state.typeId) { if (s 阅读详情

System UI的内容很多,包括状态栏、通知栏、锁屏、Navigation bar和Recent等;本篇主要分析状态栏中的RAT图标、数据图标以及信号格的更新。每一个新版本,Google都会对这一块进行修改,所以不同版本之间会有些差异,本篇内容是基于Android O。
本文分成三部分:
1. System UI的启动
2. System UI的布局
3. 图标的更新


1. System UI的启动

下方的流程图从SystemServer启动,即SystemServer.main方法开始简单展示了StatusBar的启动流程。
中中

SystemServer.startSystemUi方法负责去启动SystemUIService:

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

在启动SystemUIService时,SystemUIApplication会先被启动。SystemUIService的onCreate方法会调用SystemUIApplication.startServicesIfNeeded方法,后者构造了一系列SystemUI类型(子类)的对象,并调用了它们的start方法,其中就包括SystemBars,SystemBars.start方法如下:

 @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        createStatusBarFromConfig();
    }

    private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        //"获取类信息,R.string.config_statusBarComponent的默认值是com.android.systemui.statusbar.phone.StatusBar"
        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 = (SystemUI) cls.newInstance();//new一个实例
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();//调用StatusBar.start方法
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }

R.string.config_statusBarComponent的值是com.android.systemui.statusbar.phone.StatusBar

相比于之前的版本,Android O上没有了PhoneStatusBar.java类,取而代之的是StatusBar.java。布局文件super_status_bar.xml也发生了一些改变,不再include “status_bar.xml”,而是用CollapsedStatusBarFragment加载; CollapsedStatusBarFragment本身的加载是在StatusBar.makeStatusBarView方法中,下面即是这部分代码:

    FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanel);
                    mStatusBarView.setScrimController(mScrimController);
                    setAreThereNotifications();
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();

这段代码或许看起来不是那么清晰明了,因为里面包含了多个方法调用还夹杂了Java 8的的Lambda表达式; 其实addTagListener方法中的Lambda部分是回调,所以可以先忽略掉,只关注addTagListener方法的返回对象。
下面是FragmentHostManager.get方法的code:

    public static FragmentHostManager get(View view) {
        try {
            return Dependency.get(FragmentService.class).getFragmentHostManager(view);
        } catch (ClassCastException e) {
            // TODO: Some auto handling here?
            throw e;
        }
    }

这个方法只是调用了FragmentService的getFragmentHostManager方法,code如下:

    public FragmentHostManager getFragmentHostManager(View view) {
        View root = view.getRootView();
        FragmentHostState state = mHosts.get(root);
        if (state == null) {
            state = new FragmentHostState(root);
            mHosts.put(root, state);
        }
        return state.getFragmentHostManager();
    }

FragmentService.getFragmentHostManager方法创建了一个FragmentHostState对象,然后调用这个对象的getFragmentHostManager方法,下面是FragmentHostState的相关code:

        public FragmentHostState(View view) {
            mView = view;
            //创建一个FragmentHostManager对象
            mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView);
        }
        public FragmentHostManager getFragmentHostManager() {
            return mFragmentHostManager;
        }

通过上面的一些列调用,我们可以看到FragmentHostManager.get方法使用参数View创建了一个新的FragmentHostManager对象,而FragmentHostManager.addTagListener方法返回的仍是对象本身。

那么FragmentHostManager.getFragmentManager()方法返回的又是什么呢?
下面是看下FragmentHostManager的构造方法和createFragmentHost方法:

    FragmentHostManager(Context context, FragmentService manager, View rootView) {
        mContext = context;
        mManager = manager;
        mRootView = rootView;
        mConfigChanges.applyNewConfig(context.getResources());
        createFragmentHost(null);
    }

    private void createFragmentHost(Parcelable savedState) {
        mFragments = FragmentController.createController(new HostCallbacks());
        mFragments.attachHost(null);
        mLifecycleCallbacks = new FragmentLifecycleCallbacks() {
            @Override
            public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
                    Bundle savedInstanceState) {
                FragmentHostManager.this.onFragmentViewCreated(f);
            }

            @Override
            public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
                FragmentHostManager.this.onFragmentViewDestroyed(f);
            }

            @Override
            public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
                Dependency.get(LeakDetector.class).trackGarbage(f);
            }
        };
        mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks,
                true);
        if (savedState != null) {
            mFragments.restoreAllState(savedState, (FragmentManagerNonConfig) null);
        }
        // For now just keep all fragments in the resumed state.
        mFragments.dispatchCreate();
        mFragments.dispatchStart();
        mFragments.dispatchResume();
    }

FragmentHostManager的构造函数没什么重要内容,只是调用了内部Private 方法createFragmentHost,该方法构造了一个FragmentController类型的对象mFragments,并设置了HostCallbacks对象作为回调; HostCallbacks(继承了FragmentHostCallback)内部有FragmentManagerImpl对象,FragmentManagerImpl是FragmentManager.java的内部类,继承了FragmentManager类。
下面是FragmentHostManager.getFragmentManager()的代码:

    public FragmentManager getFragmentManager() {
        return mFragments.getFragmentManager();
    }

又调用了FragmentController的getFragmentManager()方法,对应code如下:

    /**
     * Returns a {@link FragmentManager} for this controller.
     */
    public FragmentManager getFragmentManager() {
        return mHost.getFragmentManagerImpl();
    }

代码中的mHost即是HostCallbacks对象,HostCallbacks.getFragmentManagerImpl()方法返回的就是FragmentManagerImpl对象。即FragmentHostManager.getFragmentManager()方法返回了一个FragmentManagerImpl对象。再回到StatusBar.makeStatusBarView方法中:

    FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanel);
                    mStatusBarView.setScrimController(mScrimController);
                    setAreThereNotifications();
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();

FragmentManagerImpl.beginTransaction方法会返回一个BackStackRecord对象; BackStackRecord继承了FragmentTransaction, 折腾了一圈还是回到了FragmentTransaction,然后使用replace方法将CollapsedStatusBarFragment放进布局中super_status_bar.xml中; CollapsedStatusBarFragment会加载R.layout.status_bar布局(PhoneStatusBarView)。

代码流程是看懂了,但是由于对Android UI这套理解不深,所以不明白这个设计的初衷,是为了解耦,模块化?

Dependency.java

SystemUIApplication启动的service就包含Dependency, Dependency包含一个ArrayMap <Object, DependencyProvider>类型的成员变量mProviders, Dependency.start方法中会重要类的对象放到mProviders中, 下面是部分代码:

        mProviders.put(NetworkController.class, () ->
                new NetworkControllerImpl(mContext, getDependency(BG_LOOPER),
                        getDependency(DeviceProvisionedController.class)));

        mProviders.put(ZenModeController.class, () ->
                new ZenModeControllerImpl(mContext, getDependency(MAIN_HANDLER)));

        mProviders.put(HotspotController.class, () ->
                new HotspotControllerImpl(mContext));

        mProviders.put(CastController.class, () ->
                new CastControllerImpl(mContext));

        mProviders.put(FlashlightController.class, () ->
                new FlashlightControllerImpl(mContext));

2. System UI的布局

System UI的布局大致分成两部分,左边用来显示通知信息,右边用来显示时钟、信号格等信息; 而且这两部分向相反方向扩展,即左边部分从右向左扩展,右边部分从左向右扩展。本文主要关注右边部分的布局,下图简单的展示了相关的布局关系:
这里写图片描述
super_status_bar.xml没有直接include “status_bar.xml”,而是用CollapsedStatusBarFragment加载到了下面的FrameLayout布局中:

    <FrameLayout
        android:id="@+id/status_bar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

status_bar.xml部分布局如下:

<!--省略-->
<!--下面是一个线性布局-->
<LinearLayout android:id="@+id/status_bar_contents"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="6dp"
        android:paddingEnd="8dp"
        android:orientation="horizontal"
        >

        <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
             PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/notification_icon_area"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" />

        <!--系统icon显示区域-->
        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            >

            <!--include system_icons显示信号格,RAT等-->
            <include layout="@layout/system_icons" />

            <!--时钟-->
            <com.android.systemui.statusbar.policy.Clock
                android:id="@+id/clock"
                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:singleLine="true"
                android:paddingStart="@dimen/status_bar_clock_starting_padding"
                android:paddingEnd="@dimen/status_bar_clock_end_padding"
                android:gravity="center_vertical|start"
                />
        </com.android.keyguard.AlphaOptimizedLinearLayout>
    </LinearLayout>
    <!--省略-->

system_icons.xml布局比较简单,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">

    <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>

    <!--加载signal_cluster_view布局-->
    <include layout="@layout/signal_cluster_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>

    <!--电量显示-->
    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        />
</LinearLayout>

signal_cluster_view.xml对应的是SignalClusterView对象,当SignalClusterView.onAttachedToWindow方法被系统调用时,SignalClusterView会调用NetworkControllerImpl.addCallback方法,在这个方法中SignalClusterView.setSubs方法会被调用:

    @Override
    public void setSubs(List<SubscriptionInfo> subs) {
        //如果已经包含了subs信息,那么直接return
        if (hasCorrectSubs(subs)) {
            return;
        }
        //下面两句清空了之前的数据
        mPhoneStates.clear();
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.removeAllViews();
        }
        final int n = subs.size();
        //根据subscription信息开始加载布局
        for (int i = 0; i < n; i++) {
            inflatePhoneState(subs.get(i).getSubscriptionId());
        }
        if (isAttachedToWindow()) {
            applyIconTint();
        }
    }

    //PhoneState是SignalClusterView的内部类,每个PhoneState对象都会加载一个mobile_signal_group.xml布局,
    //所以mobile_signal_group.xml布局数量和active Subscription数量(SIM 数量)一致。
    private PhoneState inflatePhoneState(int subId) {
        PhoneState state = new PhoneState(subId, mContext);
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.addView(state.mMobileGroup);
        }
        mPhoneStates.add(state);
        return state;
    }

3. 图标更新

下面的流程图简单展示了UI更新的过程:
这里写图片描述
NetworkControllerImpl的构造函数使用mReceiverHandler.post方法将Runnable对象mRegisterListeners放到了消息队列里面,当mRegisterListeners执行的时候run方法会调用NetworkControllerImpl.registerListeners方法,这个方法监听了很多广播(NetworkControllerImpl是BroadcastReceiver的子类)。

    private void registerListeners() {
        for (int i = 0; i < mMobileSignalControllers.size(); i++) {
            MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
            mobileSignalController.registerListener();
        }
        if (mSubscriptionListener == null) {
            mSubscriptionListener = new SubListener();
        }
        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);

        // broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        mContext.registerReceiver(this, filter, null, mReceiverHandler);
        mListening = true;

        updateMobileControllers();
    }

不同的广播,处理自然也不一样。
当收到广播ACTION_SIM_STATE_CHANGED的时候,updateMobileControllers、doUpdateMobileControllers、setCurrentSubscriptions等方法会先后被调用。setCurrentSubscriptions方法会根据最新的subscriptions信息构造MobileSignalController方法,并调用新对象的registerListener方法在TelephonyManager中设置监听:

    /**
     * Start listening for phone state changes.
     */
    public void registerListener() {
        mPhone.listen(mPhoneStateListener,
                PhoneStateListener.LISTEN_SERVICE_STATE
                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
                        | PhoneStateListener.LISTEN_CALL_STATE
                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                        | PhoneStateListener.LISTEN_DATA_ACTIVITY
                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
        mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
                true, mObserver);
        mContext.getContentResolver().registerContentObserver(Global.getUriFor(
                Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
                true, mObserver);
    }

MobileSignalController监听了service state、signal strength和call state等,当这些状态变化时MobileSignalController会通知自己的监听者,调用方法顺序是:
notifyListenersIfNecessary()
–>notifyListeners()
–>notifyListeners(mCallbackHandler)
mCallbackHandler是NetworkControllerImpl在构造MobileSignalController对象的时候传进来的,即NetworkControllerImpl.mCallbackHandler。NetworkControllerImpl.mCallbackHandler可以把状态变化通知到SignalClusterView对象,因为SignalClusterView.onAttachedToWindow方法被调用的时候,SignalClusterView调用了NetworkControllerImpl.addCallback方法在NetworkControllerImpl.mCallbackHandler中设置了监听。针对MobileSignalController的调用NetworkControllerImpl.mCallbackHandler会调用setMobileDataIndicators方法,其实这个方法只是做了赋值操作,真正更新是在apply方法中。


结束!

【Code】KaiOS SPN运营商名称显示代码逻辑和日志分析 与SPN运营商名称显示有关的代码流程和日志分析,包括SIM卡相关信息获取和SPN更新逻辑,从systemui应用层到RIL层与MD请求交互的过程。 阅读详情

相关推荐

Flutter 原生通信 (一) - flutter调用Android

原生通信系列 1. Flutter 调用 Android 2. Android 通知 Flutter 3. Flutter 调用 iOS 4. iOS 通知 Flutter 项目地址 在 flutter 开发中一定会有需要和原生通信的情况 第一篇介绍的是 flutter 调用 Android 这篇是给刚刚入门或者刚刚接触原生调用的朋友们使用的,老鸟们或者英文强的朋友还是直接看官方文档比较好 创建...

SimpleCoder's Blog 1万+

状态栏RAT信号图标显示

状态栏RAT信号图标指的是驻网类型图标(5G,4G,3G,2G等)。 原生逻辑:该图标和数据连接有关,数据连接开启时才显示RAT信号图标,数据连接关闭时隐藏RAT信号图标。 平台逻辑:RAT信号图标和数据连接状态无关,即无论数据连接是否开启,只要当前sim卡状态时有服务,就显示当前网络类型图标。 修改为原生显示方式: 配置/packages/apps/CarrierConfig/res/xml/vendor.xml 将以下行删除即可 ...

bestwu0666的博客 1493

squirrel校园二手交易平台

squirrel校园二手交易平台 (适合寻找SSM项目练手的你。) 项目起源:   期末的课程设计,三人一组,我和两个舍友,一时起兴,决定做一个校园二手交易平台,一开始兴致与激情满满,可是后期时间上的冲突,让我们三个人对于这个项目有点累。   这个项目刚定题两天,BezosLee由于通过了360的网上在线笔试,收到了360公司的免费培训邀请,要去北京的360总部进行培训一周,值得庆...

K.SHI的博客 5万+

android setting模块,android O版本 设置(Settings)模块总结--设置的一级界面的加载

O版本的设置界面相对有N有了一些变化,O上面增加了顶级类别的菜单,而之前一些在一级菜单的则移动到了二级界面里面,如"WIFI","移动网络"等之前是在一级界面的,而在O上则移动到了新菜单"网络和互联网"中,但是在数据在加载方面,并未做较大的变化.(a)一级界面--顶级菜单的数据加载在上一篇 <> 中有说到DashboardSummary是顶级菜单的容器,那么数据的获取和它也就有关系了:...

weixin_34026997的博客 1148

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek

Win10环境借助DockerDesktop部署Open web UI集成DeepSeek,并借助DuckDuckGo实现联网查询

虎鲸不是鱼 1699

Nornir自动化简单介绍-网络设备信息收集

作为网工,学会通过执行脚本,可以自动化的完成日常一些设备相关配置或信息收集等工作,可以说是事半功倍。 Nornir就是这样一个自动化网络运维工具。按照官网上的说明: Nornir是用python编写的自动化框架,可与python一起使用。Nornir旨在通过提供一个纯Python框架来解决这些问题。 详细参考: Github GitHub - nornir-automation/nornir: Pluggable multi-threaded framework with inventory .

Gun&rose 7805

【Android进阶】android:configChanges属性总结

android中的组件Activity在manifest.xml文件中可以指定参数android:ConfigChanges,用于捕获手机状态的改变。 在Activity中添加了android:configChanges属性,在当所指定属性(Configuration Changes)发生改变时,通知程序调用onConfigurationChanged()函数。 设置方法:将下列字...

weixin_30251829的博客 1000

MATLAB安装

Matlab 2016a 安装包及破解教程百度云分享链接: 链接:https://pan.baidu.com/s/1i6BgD8p       密码:17gg   Matlab安装教程: 1、下载文件,得到R2016a_win64.part1.rar、R2016a_win64.part2.rar两部分安装文件和Matlab 2016a Win64 Crack破解文件。 2、解压安装文件(解...

qq_36734094的博客 17万+

android java configchanges,InterestingConfigChanges.java

/** Copyright (C) 2011 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obta...

weixin_35871519的博客 193

【ChangeCLIP】Remote sensing change detection with multimodal vision-language representation learning

ChangeCLIP论文及代码使用详解。持续更新变化检测最新论文,欢迎订阅本专栏。

向上生长的程序媛的博客 1335

Vision 机器视觉案例 之 零件边缘缺陷检测

缺陷检测工具

机器视觉李小白的博客 1385

StatusBar浅析

从结构上来说,下拉菜单和状态栏都属于StatusBar,在Android9.0之后,可以对状态栏进行变色操作或者添加图标,真正实现了自定义!

m0_53696288的博客 798

【PPS便携式移动电源】如何透彻了解便携式移动电源,仅需要十分钟阅读即可

PPS 便携式储能电源的发展前景广阔,受益于户外经济爆发、应急备灾需求提升及 “双碳” 政策支持,全球市场规模预计持续增长,2025 年出货量将达 2380 万台,未来将向大功率大容量、光充一体化、智能化方向发展,还会拓展家庭储能、移动医疗等新场景,同时钠离子电池应用、双向逆变技术升级将进一步推动行业发展。

昔时扬尘处 272

android 9.0打开wifi,Android9.0 SystemUI 屏蔽打开wifi时不显示4G图标的逻辑

Android 9.0 中打开wifi时,不显示4G图标,只有信号值,现项目需求在打开wifi时仍然显示4G图标。排查及修改过程如下:systemui/src/com/android/systemui/statusbar/StatusBarMobileView.javaprivate void updateState(MobileIconState state) {//省略部分代码if (mSta...

weixin_29543939的博客 585

2.Vivado软件基础操作

在本章节,我们以一个简单的计数器实例,介绍FPGA开发软件Vivado的基础操作流程,计数器实例程序的设计,在本课程中先不同掌握,后续课程将针对verilog编程进行讲解。 打开Vivado软件,会看到如下的界面: 点击如下图所示的: 点击Next> 将这个地方,设置路径,注意路径必须是英文路径。且文件夹名称第一个字符不能为数字。所有路径的名称的字符数量不能超过144个符号。 点击Next> 点击Next> 点...

FPGA/MATLAB学习教程/源码/项目合作开发 4478

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

android 系统System UI Tuner大概讲解

这两天修改android 6.0 的一个BUG,要求删掉下拉菜单里面的手电筒图标。          首先讲讲怎么进入的吧。相信这个大家在网上都已经找到过了。在android 6.0 之前是没有这个功能的。          打开的方法:通知栏拉到底,长按设置图标,就是电池与个人中间的齿轮图标,大概5秒, 然后进入设置,就可以看到关于手机的下面多出了个System UI Tuner,打开后会看

Danna_lucky 7753

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【亲测免费】 推荐项目:SystemUI Tuner - 打造个性化的安卓系统界面

推荐项目:SystemUI Tuner - 打造个性化的安卓系统界面 项目介绍 SystemUI Tuner是一款为安卓用户提供深度定制系统界面的工具,它替代并扩展了原生安卓的系统界面调整器。由于一些制造商在他们的皮肤中禁用了系统界面调校器,许多用户错失了许多高级自定义选项。现在,无论你的设备是否带有原生的系统界面调校器,SystemUI Tuner都能为你提供更多的个性化设置。 项目技术分析 无...

gitblog_00043的博客 3424

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

动态显示和隐藏NavigationBar

修改地方在NavigationBarFragment.java类中 public static View create(Context context, FragmentListener listener) { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,

梦家之家 786

android SystemUI导航栏和状态栏-2020-12-02

https://www.cnblogs.com/liguangsunls/p/7308864.html

行者-崛起之路 1535

SystemUI-StatusBar-虚拟按键

1) StatusBar.start ->createAndAddWindows()->addStatusBarWindow()->makeStatusBarView()-> 2) makeStatusBarView()->createNavigationBar()->NavigationBarFragment.create()-> 3) create(Context context, FragmentListener listener)-> ...

weixin_42196034的博客 238

Flutter与Android开发:构建跨平台移动应用的新选择

移动应用开发领域一直在不断发展,各种新的技术和工具层出不穷。其中,Flutter作为一种由Google推出的开源UI工具包,引起了广泛关注和使用。本部分将对Flutter进行介绍,包括其基本概念、特点和优势,从而为读者打下基础,了解Flutter技术的背景和优势。1.1 Flutter的基本概念:本节将介绍Flutter的基本概念,包括其是什么、由谁开发、采用的编程语言、支持的平台等。读者将了解Flutter是一种什么样的技术,它由谁推出,支持的平台和编程语言等。

虎哥LoveDroid 2245

Flutter与Android比较

View相关 Flutter使用的是声明式UI,而Win32、Android或iOS框架中使用的是命令式UI,具体差异为:命令式UI需要开发者手动构建和控制一个UI控件的所有功能,然后在需要变更UI时,使用方法和设置器修改。而声明式UI只需要明确一个UI控件的当前状态即可,剩下的UI变换交给框架完成。 举个例子: ViewB下包含的两个ViewC(c1和c2)需要变更成ViewB下包含一个ViewC(c3),并修改背景色。 命令式UI的写法应该是: b.setColot(red); b.clear

haoxuhong的博客 4016

flutter与Android混合开发全攻略,flutter真的很重要

在新开发一个应用程序时,我们可以充分使用 Flutter进行开发,实现效果最大化。但是,对于一个已经成熟的应用程序来说,用 Flutter来重新编写所有程序不是那么现实。不过flutter开发者考虑到了这一点,Flutter能够很好地将其整合到一个已有的应用程序中,也就是所谓的混合开发模式。大家可以先思考一下flutter和Android原生之间的关系。想好了吗?

m0_56255097的博客 5474

Flutter(Android 混合开发)

前言 Flutter 支持作为 android Moudle 出现在项目中.这样就可以在 已有的项目中 使用. 虽然现在Flutter 比较受关注,但是和weex 一样 ,大部分都只是在观望 不是真正的进行使用.所以 如果用还是混合开发 原生+Flutter 方式比较合适(自我感觉). 写一个demo 进行Android及Flutter 交互.(IOS 方法基本一致). Flutter 调用 a...

李挺哲的移动专栏 1万+

Flutter与Android的差异性

一、Views 1.1)、Android的所有的控件都是View,在Android上View绘制结束后,就不会重绘,知道调用invalidate时才会重绘; Flutter中是Widget,它仅支持一帧,并且在每一帧上,flutter的框架都会创建一个widget实例树(相当于一次绘制整个界面)。 1.2)、Android中可以通过直接对view进行改变来更新视图;而widget是不可变的,不会直...

qq_31010739的博客 2178

flutter与android原生通信

刚接触flutter的时候,以为flutter是一个全新开发app的语言,独立于Android原生之外的操作,入坑之后发现不是的。因为Flutter不能完成所有Native的功能,比如不同平台的底层服务如电量变化、网络连接变化以及最近项目中使用的直接拨号功能以及地图功能都无法用flutter实现其功能,因此需要借助Native层的接口来实现flutter的开发,所以Flutter提供了一套Platform Channel的机制,来满足Flutter与Native通信的需求。图中可以看到,Flutter是Cl

Restless Breeze 6056
上一篇: ConnectivityManager and ConnectivityService --- Telephony data Part III
下一篇: SIM-based call process
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值