我是靠谱客的博主 勤恳钢笔,最近开发中收集的这篇文章主要介绍Android P自动确定时区代码流程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

根据字符自动确定时区查找到Setting中对应的字符

packages/apps/Settings/res/values-zh-rCN/strings.xml:    <string name="zone_auto" msgid="334783869352026648">"自动确定时区"</string>

而后可以知道其对应的文件是:packages/apps/Settings/res/xml/date_time_prefs.xml,代码片段是:

<PreferenceCategory
        android:key="time_zone_preference_category"
        android:layout="@layout/preference_category_no_label">
        <com.android.settingslib.RestrictedSwitchPreference
            android:key="auto_zone"
            android:title="@string/zone_auto"
            android:summaryOn="@string/zone_auto_summaryOn"
            android:summaryOff="@string/zone_auto_summaryOff"
            settings:userRestriction="no_config_date_time" />

        <com.android.settingslib.RestrictedPreference
            android:fragment="com.android.settings.datetime.ZonePicker"
            android:key="timezone"
            android:title="@string/date_time_set_timezone"
            android:summary="@string/summary_placeholder"
            settings:userRestriction="no_config_date_time" />
    </PreferenceCategory>

根据以上的Key值auto_zone,可以知道所在的文件为:
packages/apps/Settings/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
获取到关键的控制参数是:Settings.Global.AUTO_TIME_ZONE

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean autoZoneEnabled = (Boolean) newValue;
        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
                autoZoneEnabled ? 1 : 0);
        mCallback.updateTimeAndDateDisplay(mContext);
        return true;
    }

在Service中有对Settings.Global.AUTO_TIME_ZONE的设置的反应,查找可以找到对应的Service是
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java

    @Override
    public boolean setTimeZone(ComponentName who, String timeZone) {
        Preconditions.checkNotNull(who, "ComponentName is null in setTimeZone");
        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
        // Don't allow set timezone when auto timezone is on.
        if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
            return false;
        }
        mInjector.binderWithCleanCallingIdentity(() ->
            mInjector.getAlarmManager().setTimeZone(timeZone));
        return true;
    }

对Settings.Global.AUTO_TIME_ZONE参数变化的监听是:frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java

    public interface Listener {
        /**
         * Automatic time detection has been enabled or disabled.
         */
        void onTimeDetectionChange(boolean enabled);

        /**
         * Automatic time zone detection has been enabled or disabled.
         */
        void onTimeZoneDetectionChange(boolean enabled);
    }

    /**
     * Sets a listener that will be called when the automatic time / time zone detection setting
     * changes.
     */
    public void setListener(Listener listener) {
        if (listener == null) {
            throw new NullPointerException("listener==null");
        }
        if (mListener != null) {
            throw new IllegalStateException("listener already set");
        }
        this.mListener = listener;
        mCr.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
                new ContentObserver(new Handler()) {
                    public void onChange(boolean selfChange) {
                        listener.onTimeDetectionChange(isTimeDetectionEnabled());
                    }
                });
        mCr.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
                new ContentObserver(new Handler()) {
                    public void onChange(boolean selfChange) {
                        listener.onTimeZoneDetectionChange(isTimeZoneDetectionEnabled());
                    }
                });
    }

当时区开关改变时候,会有监听函数:onTimeZoneDetectionChange响应;
继续跟踪可以找到实现该代码的位置:
frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java

 mTimeServiceHelper.setListener(new TimeServiceHelper.Listener() {
            @Override
            public void onTimeDetectionChange(boolean enabled) {
                if (enabled) {
                    handleAutoTimeEnabled();
                }
            }

            @Override
            public void onTimeZoneDetectionChange(boolean enabled) {
                if (enabled) {
                    handleAutoTimeZoneEnabled();
                }
            }
        });
        
 private void handleAutoTimeZoneEnabled() {
        String tmpLog = "handleAutoTimeZoneEnabled: Reverting to NITZ TimeZone:"
                + " mSavedTimeZoneId=" + mSavedTimeZoneId;
        if (DBG) {
            Rlog.d(LOG_TAG, tmpLog);
        }
        mTimeZoneLog.log(tmpLog);
        if (mSavedTimeZoneId != null) {
            setAndBroadcastNetworkSetTimeZone(mSavedTimeZoneId);
        } else {
            String iso = mDeviceState.getNetworkCountryIsoForPhone();
            if (!TextUtils.isEmpty(iso)) {
                updateTimeZoneByNetworkCountryCode(iso);
            }
        }
    }

接收到网络更新的时区更新:

  /**
     * Handle a new NITZ signal being received.
     */
    public void handleNitzReceived(TimeStampedValue<NitzData> nitzSignal) {
        handleTimeZoneFromNitz(nitzSignal);
        handleTimeFromNitz(nitzSignal);
    }

    private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) {
        try {
            NitzData newNitzData = nitzSignal.mValue;
            String iso = mDeviceState.getNetworkCountryIsoForPhone();
            String zoneId;
            if (newNitzData.getEmulatorHostTimeZone() != null) {
                zoneId = newNitzData.getEmulatorHostTimeZone().getID();
            } else {
                if (!mGotCountryCode) {
                    zoneId = null;
                } else if (!TextUtils.isEmpty(iso)) {
                    OffsetResult lookupResult =
                            mTimeZoneLookupHelper.lookupByNitzCountry(newNitzData, iso);
                    zoneId = lookupResult != null ? lookupResult.zoneId : null;
                } else {
                    // We don't have a valid iso country code.  This is
                    // most likely because we're on a test network that's
                    // using a bogus MCC (eg, "001"), so get a TimeZone
                    // based only on the NITZ parameters.
                    OffsetResult lookupResult = mTimeZoneLookupHelper.lookupByNitz(newNitzData);
                    if (DBG) {
                        Rlog.d(LOG_TAG, "handleTimeZoneFromNitz: guessZoneIdByNitz returned"
                                + " lookupResult=" + lookupResult);
                    }
                    zoneId = lookupResult != null ? lookupResult.zoneId : null;
                }
            }

            if ((zoneId == null)
                    || mLatestNitzSignal == null
                    || offsetInfoDiffers(newNitzData, mLatestNitzSignal.mValue)) {
                // We got the time before the country, or the zone has changed
                // so we don't know how to identify the DST rules yet.  Save
                // the information and hope to fix it up later.
                mNeedCountryCodeForNitz = true;
                mLatestNitzSignal = nitzSignal;
            }

            String tmpLog = "handleTimeZoneFromNitz: nitzSignal=" + nitzSignal
                    + " zoneId=" + zoneId
                    + " iso=" + iso + " mGotCountryCode=" + mGotCountryCode
                    + " mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz
                    + " isTimeZoneDetectionEnabled()="
                    + mTimeServiceHelper.isTimeZoneDetectionEnabled();
            if (DBG) {
                Rlog.d(LOG_TAG, tmpLog);
            }
            mTimeZoneLog.log(tmpLog);

            if (zoneId != null) {
                if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
                    setAndBroadcastNetworkSetTimeZone(zoneId);
                }
                mNitzTimeZoneDetectionSuccessful = true;
                mSavedTimeZoneId = zoneId;
            }
        } catch (RuntimeException ex) {
            Rlog.e(LOG_TAG, "handleTimeZoneFromNitz: Processing NITZ data"
                    + " nitzSignal=" + nitzSignal
                    + " ex=" + ex);
        }
    }

    private static boolean offsetInfoDiffers(NitzData one, NitzData two) {
        return one.getLocalOffsetMillis() != two.getLocalOffsetMillis()
                || one.isDst() != two.isDst();
    }

    private void handleTimeFromNitz(TimeStampedValue<NitzData> nitzSignal) {
        try {
            boolean ignoreNitz = mDeviceState.getIgnoreNitz();
            if (ignoreNitz) {
                Rlog.d(LOG_TAG,
                        "handleTimeFromNitz: Not setting clock because gsm.ignore-nitz is set");
                return;
            }

            try {
                // Acquire the wake lock as we are reading the elapsed realtime clock and system
                // clock.
                mWakeLock.acquire();

                // Validate the nitzTimeSignal to reject obviously bogus elapsedRealtime values.
                long elapsedRealtime = mTimeServiceHelper.elapsedRealtime();
                long millisSinceNitzReceived = elapsedRealtime - nitzSignal.mElapsedRealtime;
                if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) {
                    if (DBG) {
                        Rlog.d(LOG_TAG, "handleTimeFromNitz: not setting time, unexpected"
                                + " elapsedRealtime=" + elapsedRealtime
                                + " nitzSignal=" + nitzSignal);
                    }
                    return;
                }

                // Adjust the NITZ time by the delay since it was received to get the time now.
                long adjustedCurrentTimeMillis =
                        nitzSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived;
                long gained = adjustedCurrentTimeMillis - mTimeServiceHelper.currentTimeMillis();

                if (mTimeServiceHelper.isTimeDetectionEnabled()) {
                    String logMsg = "handleTimeFromNitz:"
                            + " nitzSignal=" + nitzSignal
                            + " adjustedCurrentTimeMillis=" + adjustedCurrentTimeMillis
                            + " millisSinceNitzReceived= " + millisSinceNitzReceived
                            + " gained=" + gained;

                    if (mSavedNitzTime == null) {
                        logMsg += ": First update received.";
                        setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis);
                    } else {
                        long elapsedRealtimeSinceLastSaved = mTimeServiceHelper.elapsedRealtime()
                                - mSavedNitzTime.mElapsedRealtime;
                        int nitzUpdateSpacing = mDeviceState.getNitzUpdateSpacingMillis();
                        int nitzUpdateDiff = mDeviceState.getNitzUpdateDiffMillis();
                        if (elapsedRealtimeSinceLastSaved > nitzUpdateSpacing
                                || Math.abs(gained) > nitzUpdateDiff) {
                            // Either it has been a while since we received an update, or the gain
                            // is sufficiently large that we want to act on it.
                            logMsg += ": New update received.";
                            setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis);
                        } else {
                            if (DBG) {
                                Rlog.d(LOG_TAG, logMsg + ": Update throttled.");
                            }

                            // Return early. This means that we don't reset the
                            // mSavedNitzTime for next time and that we may act on more
                            // NITZ time signals overall but should end up with a system clock that
                            // tracks NITZ more closely than if we saved throttled values (which
                            // would reset mSavedNitzTime.elapsedRealtime used to calculate time
                            // since the last NITZ signal was received).
                            return;
                        }
                    }
                }

                // Save the last NITZ time signal used so we can return to it later
                // if auto-time detection is toggled.
                mSavedNitzTime = new TimeStampedValue<>(
                        adjustedCurrentTimeMillis, nitzSignal.mElapsedRealtime);
            } finally {
                mWakeLock.release();
            }
        } catch (RuntimeException ex) {
            Rlog.e(LOG_TAG, "handleTimeFromNitz: Processing NITZ data"
                    + " nitzSignal=" + nitzSignal
                    + " ex=" + ex);
        }
    }

    private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
        if (DBG) {
            Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: zoneId=" + zoneId);
        }
        mTimeServiceHelper.setDeviceTimeZone(zoneId);
        if (DBG) {
            Rlog.d(LOG_TAG,
                    "setAndBroadcastNetworkSetTimeZone: called setDeviceTimeZone()"
                            + " zoneId=" + zoneId);
        }
    }

    private void setAndBroadcastNetworkSetTime(String msg, long time) {
        if (!mWakeLock.isHeld()) {
            Rlog.w(LOG_TAG, "setAndBroadcastNetworkSetTime: Wake lock not held while setting device"
                    + " time (msg=" + msg + ")");
        }

        msg = "setAndBroadcastNetworkSetTime: [Setting time to time=" + time + "]:" + msg;
        if (DBG) {
            Rlog.d(LOG_TAG, msg);
        }
        mTimeLog.log(msg);
        mTimeServiceHelper.setDeviceTime(time);
        TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time);
    }

frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java找到mNitzState.handleNitzReceived(nitzSignal)函数的调用:

/**
     * nitzReceiveTime is time_t that the NITZ time was posted
     */
    private void setTimeFromNITZString(String nitzString, long nitzReceiveTime) {
        long start = SystemClock.elapsedRealtime();
        if (DBG) {
            Rlog.d(LOG_TAG, "NITZ: " + nitzString + "," + nitzReceiveTime
                    + " start=" + start + " delay=" + (start - nitzReceiveTime));
        }
        NitzData newNitzData = NitzData.parse(nitzString);
        if (newNitzData != null) {
            try {
                TimeStampedValue<NitzData> nitzSignal =
                        new TimeStampedValue<>(newNitzData, nitzReceiveTime);
                mNitzState.handleNitzReceived(nitzSignal);
            } finally {
                if (DBG) {
                    long end = SystemClock.elapsedRealtime();
                    Rlog.d(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
                }
            }
        }
    }

ServiceStateTracker文件中对EVENT_NITZ_TIME事件的处理:

    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;
        int[] ints;
        Message message;
 if (VDBG) log("received event " + msg.what);
        switch (msg.what) {
            case EVENT_SET_RADIO_POWER_OFF:
                synchronized(this) {
                    if (mPendingRadioPowerOffAfterDataOff &&
                            (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
                        if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
                        hangupAndPowerOff();
                        mPendingRadioPowerOffAfterDataOffTag += 1;
                        mPendingRadioPowerOffAfterDataOff = false;
                    } else {
                        log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
                                "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
                    }
                }
                break;
            
            //省略较多代码..
            case EVENT_NITZ_TIME:
                ar = (AsyncResult) msg.obj;

                String nitzString = (String)((Object[])ar.result)[0];
                long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();

                setTimeFromNITZString(nitzString, nitzReceiveTime);
                break;

            case EVENT_SIGNAL_STRENGTH_UPDATE:
                // This is a notification from CommandsInterface.setOnSignalStrengthUpdate

                ar = (AsyncResult) msg.obj;

                // The radio is telling us about signal strength changes
                // we don't have to ask it
                mDontPollSignalStrength = true;

                onSignalStrengthResult(ar);
                break;
public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
        mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone);
        mPhone = phone;
        mCi = ci;

        //省略较多代码
        mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
        mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
        mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);

frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyComponentFactory.java

public static TelephonyComponentFactory getInstance() {
        if (sInstance == null) {
            String fullClsName = "com.qualcomm.qti.internal.telephony.QtiTelephonyComponentFactory";
            String libPath = "/system/framework/qti-telephony-common.jar";

            PathClassLoader classLoader = new PathClassLoader(libPath,
                    ClassLoader.getSystemClassLoader());
            Rlog.d(LOG_TAG, "classLoader = " + classLoader);

            if (fullClsName == null || fullClsName.length() == 0) {
                Rlog.d(LOG_TAG, "no customized TelephonyPlugin available, fallback to default");
                fullClsName = "com.android.internal.telephony.TelephonyComponentFactory";
            }

            Class<?> cls = null;
            try {
                cls = Class.forName(fullClsName, false, classLoader);
                Rlog.d(LOG_TAG, "cls = " + cls);
                Constructor custMethod = cls.getConstructor();
                Rlog.d(LOG_TAG, "constructor method = " + custMethod);
                sInstance = (TelephonyComponentFactory) custMethod.newInstance();
            } catch (NoClassDefFoundError e) {
                e.printStackTrace();
                Rlog.e(LOG_TAG, "error loading TelephonyComponentFactory");
                sInstance = new TelephonyComponentFactory();
            } catch (Exception e) {
                e.printStackTrace();
                Rlog.e(LOG_TAG, "Error loading TelephonyComponentFactory");
                sInstance = new TelephonyComponentFactory();
            }
        }
        return sInstance;
    }
        /**
     * Returns a new {@link NitzStateMachine} instance.
     */
    public NitzStateMachine makeNitzStateMachine(GsmCdmaPhone phone) {
        return new NitzStateMachine(phone);
    }

frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java

 public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) {
        mRil.processIndication(indicationType);

        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime);

        // todo: Clean this up with a parcelable class for better self-documentation
        Object[] result = new Object[2];
        result[0] = nitzTime;
        result[1] = receivedTime;

        boolean ignoreNitz = SystemProperties.getBoolean(
                TelephonyProperties.PROPERTY_IGNORE_NITZ, false);

        if (ignoreNitz) {
            if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
        } else {
            if (mRil.mNITZTimeRegistrant != null) {
                mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null));
            }
            // in case NITZ time registrant isn't registered yet, or a new registrant
            // registers later
            mRil.mLastNITZTimeInfo = result;
        }
    }

接着上述, 查看mTimeServiceHelper 的定义处:
frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java

    /**
     * Set the device time zone and send out a sticky broadcast so the system can
     * determine if the timezone was set by the carrier.
     *
     * @param zoneId timezone set by carrier
     */
    public void setDeviceTimeZone(String zoneId) {
        setDeviceTimeZoneStatic(mContext, zoneId);
    }
        /**
     * Static method for use by MccTable. See {@link #isTimeZoneSettingInitializedStatic()} for
     * explanation.
     */
    static void setDeviceTimeZoneStatic(Context context, String zoneId) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.setTimeZone(zoneId);
        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        intent.putExtra("time-zone", zoneId);
        context.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

根据广播TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE找到文件:
frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java


最后

以上就是勤恳钢笔为你收集整理的Android P自动确定时区代码流程的全部内容,希望文章能够帮你解决Android P自动确定时区代码流程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部