zoukankan      html  css  js  c++  java
  • 解决:Android4.3锁屏界面Emergency calls only


            从图片中我们可以看到,这里在语义上有一定的重复,当然这是谷歌的原始设计。这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,不过由于Android4.3在锁屏功能上比起老版本做了很大的改动,而且通过常规方法(Strings.xml中字符串)对该问题的定位会有很大的难度,拿这个界面来说,EMERGENCY CALL并不是Strings中值,而是  <string name="lockscreen_emergency_call">Emergency call</string>,只是在显示的时候进行了大小写的转换。而且例如字符”-“在String.xml中是unicode编码表示的。例如:    <string name="kg_text_message_separator" product="default">" u2014 "</string>。接下来我们对当前锁屏界面相关代码的定位进行一个简单的了解:

            在Android4.3当中当前的锁屏界面不是一个Activity而是一个View,该View位于/frameworks/base/policy/src/com/android/internal/policy/impl/keyguard目录下的KeyguardPatternView.java,其所对应的布局文件为keyguard_pattern_view.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <!--
    **
    ** Copyright 2012, 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 obtain a copy of the License at
    **
    **     http://www.apache.org/licenses/LICENSE-2.0
    **
    ** Unless required by applicable law or agreed to in writing, software
    ** distributed under the License is distributed on an "AS IS" BASIS,
    ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    ** See the License for the specific language governing permissions and
    ** limitations under the License.
    */
    -->

    <!-- This is the screen that shows the 9 circle unlock widget and instructs
         the user how to unlock their device, or make an emergency call.  This
         is the portrait layout.  -->
    <com.android.internal.policy.impl.keyguard.KeyguardPatternView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/keyguard_pattern_view"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_maxWidth="@dimen/keyguard_security_width"
        android:layout_maxHeight="@dimen/keyguard_security_height"
        android:gravity="center_horizontal"
        android:contentDescription="@string/keyguard_accessibility_pattern_unlock">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:orientation="vertical"
                android:layout_gravity="center">

                <include layout="@layout/keyguard_message_area"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                   />

              <FrameLayout
                 android:id="@+id/keyguard_bouncer_frame"
                 android:background="@*android:drawable/kg_bouncer_bg_white"
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
                 android:layout_weight="1"
                 >
                <com.android.internal.widget.LockPatternView
                    android:id="@+id/lockPatternView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:layout_marginEnd="8dip"
                    android:layout_marginBottom="4dip"
                    android:layout_marginStart="8dip"
                    android:layout_gravity="center_horizontal"
                    android:gravity="center"
                    android:contentDescription="@string/keyguard_accessibility_pattern_area" />
              </FrameLayout>
              <include layout="@layout/keyguard_eca"
                  android:id="@+id/keyguard_selector_fade_container"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:orientation="vertical"
                  android:layout_gravity="bottom|center_horizontal"
                  android:gravity="center_horizontal" />
            </LinearLayout>
        </FrameLayout>

    </com.android.internal.policy.impl.keyguard.KeyguardPatternView>

    而keyguard_eca即使我们需要修改的锁屏界面下的紧急拨号按钮所对应的布局Alias.xml中的keyguard_emergency_carrier_area.xml布局。

    Alias.xml:

    <resources>
        <!-- Alias used to reference one of two possible layouts in keyguard.  -->
        <item type="layout" name="keyguard_eca">@android:layout/keyguard_emergency_carrier_area</item>
    </resources>
    keyguard_emergency_carrier_area.xml
    <?xml version="1.0" encoding="utf-8"?>
    <!--
    **
    ** Copyright 2012, The Android Open Source Project
    ** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
    ** Not a Contribution.
    **
    ** Licensed under the Apache License, Version 2.0 (the "License")
    ** you may not use this file except in compliance with the License.
    ** You may obtain a copy of the License at
    **
    **     http://www.apache.org/licenses/LICENSE-2.0
    **
    ** Unless required by applicable law or agreed to in writing, software
    ** distributed under the License is distributed on an "AS IS" BASIS,
    ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    ** See the License for the specific language governing permissions and
    ** limitations under the License.
    */
    -->

    <!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
    <com.android.internal.policy.impl.keyguard.EmergencyCarrierArea
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_gravity="center_horizontal"
        android:layout_alignParentBottom="true"
        android:clickable="true">

        <!-- Used only for Multi Sim case -->
        <ViewStub android:id="@+id/stub_msim_carrier_text"
            android:inflatedId="@+id/msim_keyguard_carrier_area"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout="@layout/msim_keyguard_carrier_area" />

        <com.android.internal.policy.impl.keyguard.CarrierText
            android:id="@+id/carrier_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textSize="@dimen/kg_status_line_font_size"
            android:textColor="?android:attr/textColorSecondary"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="-10dip"
            style="?android:attr/buttonBarStyle"
            android:orientation="horizontal"
            android:gravity="center"
            android:weightSum="2">

            <com.android.internal.policy.impl.keyguard.EmergencyButton
                android:id="@+id/emergency_call_button"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
                android:text="@string/kg_emergency_call_label"
                style="?android:attr/buttonBarButtonStyle"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textSize="@dimen/kg_status_line_font_size"
                android:textColor="?android:attr/textColorSecondary"
                android:drawablePadding="8dip" />

            <Button android:id="@+id/forgot_password_button"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
                style="?android:attr/buttonBarButtonStyle"
                android:textSize="@dimen/kg_status_line_font_size"
                android:textColor="?android:attr/textColorSecondary"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:drawablePadding="8dip"
                android:visibility="gone"/>
        </LinearLayout>

    </com.android.internal.policy.impl.keyguard.EmergencyCarrierArea>
    上述代码中的CarrierText即是我们需要着的控件,它继承自TextView。

    package com.android.internal.policy.impl.keyguard;

    import android.content.Context;
    import android.os.SystemProperties;
    import android.provider.Settings;
    import android.provider.Settings.SettingNotFoundException;
    import android.telephony.TelephonyManager;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.widget.TextView;

    import com.android.internal.R;
    import com.android.internal.telephony.IccCardConstants;
    import com.android.internal.telephony.IccCardConstants.State;
    import com.android.internal.widget.LockPatternUtils;

    public class CarrierText extends TextView {
        private static final String TAG = "CarrierText";
        private static CharSequence mSeparator;

        private LockPatternUtils mLockPatternUtils;

        protected boolean mAirplaneMode;

        // For prop key to show carrier.
        static final String PROP_KEY_SHOW_CARRIER = "persist.env.sys.SHOW_CARRIER";
        static final String PROP_ENV_SPEC = SystemProperties.get("persist.env.spec");

        static final int ORIGIN_CARRIER_NAME_ID = R.array.origin_carrier_names;
        static final int LOCALE_CARRIER_NAME_ID = R.array.locale_carrier_names;
        static final int LOCKSCREEN_CARRIER_DEFAULT_ID =
                R.string.lockscreen_carrier_default;


        private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
            private CharSequence mPlmn;
            private CharSequence mSpn;
            private State mSimState;

            @Override
            public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
                mPlmn = plmn;
                mSpn = spn;
                updateCarrierText(mSimState, mPlmn, mSpn);
            }

            @Override
            public void onSimStateChanged(IccCardConstants.State simState) {
                mSimState = simState;
                updateCarrierText(mSimState, mPlmn, mSpn);
            }

            @Override
            void onAirplaneModeChanged(boolean on) {
                mAirplaneMode = on;
                updateCarrierText(mSimState, mPlmn, mSpn);
            }
        };
        /**
         * The status of this lock screen. Primarily used for widgets on LockScreen.
         */
        private static enum StatusMode {
            Normal, // Normal case (sim card present, it's not locked)
            PersoLocked, // SIM card is 'perso locked'.
            SimMissing, // SIM card is missing.
            SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
            SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
            SimLocked, // SIM card is currently locked
            SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
            SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
            SimIOError; //The sim card is faulty
        }

        public CarrierText(Context context) {
            this(context, null);
        }

        public CarrierText(Context context, AttributeSet attrs) {
            super(context, attrs);
            mLockPatternUtils = new LockPatternUtils(mContext);
            try {
                mAirplaneMode = Settings.System.getInt(mContext.getContentResolver(),
                        Settings.System.AIRPLANE_MODE_ON) == 1;
            } catch (SettingNotFoundException snfe) {
                Log.e(TAG, "get airplane mode exception");
            }
        }

        protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
            CharSequence text = "";

            if (mAirplaneMode) {
                // if airplane mode is on, show "airplane mode"
                text = getContext().getText(R.string.lockscreen_airplane_mode_on);
            } else {
                text = getCarrierTextForSimState(simState, plmn, spn);
            }

            setText(text);
        }

        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            mSeparator = getResources().getString(R.string.kg_text_message_separator);
            setSelected(true); // Allow marquee to work.
        }

        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            if (KeyguardUpdateMonitor.sIsMultiSimEnabled) {
                return;
            }
            KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
        }

        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
        }

        /**
         * Top-level function for creating carrier text. Makes text based on simState, PLMN
         * and SPN as well as device capabilities, such as being emergency call capable.
         *
         * @param simState
         * @param plmn
         * @param spn
         * @return
         */
        protected CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
                CharSequence plmn, CharSequence spn) {
            CharSequence carrierText = null;
            StatusMode status = getStatusForIccState(simState);

            Log.d(TAG, "getCarrierTextForSimState, plmn: " + plmn + ", spn: " + spn);
            String localPlmn = null;
            if (plmn != null) {
                localPlmn= mContext.getLocalString(plmn.toString(),
                    com.android.internal.R.array.origin_carrier_names,
                    com.android.internal.R.array.locale_carrier_names);
            }
            String localSpn = null;
            if (spn != null) {
                localSpn= mContext.getLocalString(spn.toString(),
                    com.android.internal.R.array.origin_carrier_names,
                    com.android.internal.R.array.locale_carrier_names);
            }
            Log.d(TAG, "getCarrierTextForSimState, localPlmn: "
                + localPlmn + ", localSpn: " + localSpn);


            int resTextIdOfNoSimCard = R.string.lockscreen_missing_sim_message_short;
            if (PROP_ENV_SPEC.equalsIgnoreCase("ChinaTelecom")) {
                resTextIdOfNoSimCard = R.string.lockscreen_missing_uim_message_short;
            }

            // For CMCC requirement to show 3G in plmn if camping in TD_SCDMA.
            TelephonyManager tm =  (TelephonyManager)getContext()
                    .getSystemService(Context.TELEPHONY_SERVICE);
            boolean show3G = !mAirplaneMode && tm != null && plmn != null &&
                    tm.getVoiceNetworkType() == TelephonyManager.NETWORK_TYPE_TD_SCDMA;
            if (show3G && localPlmn != null) {
                localPlmn = localPlmn + " 3G";
            }

            switch (status) {
                case Normal:
                    carrierText = concatenate(localPlmn, localSpn);
                    break;

                case SimNotReady:
                    carrierText = null; // nothing to display yet.
                    break;

                case PersoLocked:
                    carrierText = makeCarrierStringOnEmergencyCapable(
                            getContext().getText(R.string.lockscreen_perso_locked_message),
                            plmn);
                    break;

                case SimMissing:
                    // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
                    // This depends on mPlmn containing the text "Emergency calls only" when the radio
                    // has some connectivity. Otherwise, it should be null or empty and just show
                    // "No SIM card"
                    carrierText =  makeCarrierStringOnEmergencyCapable(
                            getContext().getText(resTextIdOfNoSimCard),
                            plmn);
                    break;

                case SimPermDisabled:
                    carrierText = getContext().getText(
                            R.string.lockscreen_permanent_disabled_sim_message_short);
                    break;

                case SimMissingLocked:
                    carrierText =  makeCarrierStringOnEmergencyCapable(
                            getContext().getText(resTextIdOfNoSimCard),
                            plmn);
                    break;

                case SimLocked:
                    carrierText = makeCarrierStringOnEmergencyCapable(
                            getContext().getText(R.string.lockscreen_sim_locked_message),
                            plmn);
                    break;

                case SimPukLocked:
                    carrierText = makeCarrierStringOnEmergencyCapable(
                            getContext().getText(R.string.lockscreen_sim_puk_locked_message),
                            plmn);
                    break;

                case SimIOError:
                    carrierText = makeCarrierStringOnEmergencyCapable(
                            getContext().getText(R.string.lockscreen_sim_error_message_short),
                            plmn);
                    break;
            }

            return carrierText;
        }

        /*
         * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
         */
        private CharSequence makeCarrierStringOnEmergencyCapable(
                CharSequence simMessage, CharSequence emergencyCallMessage) {
            if (mLockPatternUtils.isEmergencyCallCapable()) {
                return concatenate(simMessage, emergencyCallMessage);
            }
            return simMessage;
        }

        /**
         * Determine the current status of the lock screen given the SIM state and other stuff.
         */
        private StatusMode getStatusForIccState(IccCardConstants.State simState) {
            // Since reading the SIM may take a while, we assume it is present until told otherwise.
            if (simState == null) {
                return StatusMode.Normal;
            }

            final boolean missingAndNotProvisioned =
                    !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
                    && (simState == IccCardConstants.State.ABSENT ||
                            simState == IccCardConstants.State.PERM_DISABLED);

            // Assume we're PERSO_LOCKED if not provisioned
            simState = missingAndNotProvisioned ? IccCardConstants.State.PERSO_LOCKED : simState;
            switch (simState) {
                case ABSENT:
                    return StatusMode.SimMissing;
                case PERSO_LOCKED:
                    return StatusMode.PersoLocked;
                case NOT_READY:
                    return StatusMode.SimNotReady;
                case PIN_REQUIRED:
                    return StatusMode.SimLocked;
                case PUK_REQUIRED:
                    return StatusMode.SimPukLocked;
                case READY:
                    return StatusMode.Normal;
                case PERM_DISABLED:
                    return StatusMode.SimPermDisabled;
                case UNKNOWN:
                    return StatusMode.SimMissing;
                case CARD_IO_ERROR:
                    return StatusMode.SimIOError;
            }
            return StatusMode.SimMissing;
        }

        private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
            final boolean plmnValid = !TextUtils.isEmpty(plmn);
            final boolean spnValid = !TextUtils.isEmpty(spn);
            /*if (plmnValid && spnValid) {
                return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
            } else if (plmnValid) {
                return plmn;
            } else if (spnValid) {
                return spn;
            } else {
                return "";
            }*/

            if (spnValid) {
                return spn;
            } else {
                return "";
            }
        }


        private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
                String plmn, String spn) {
            int carrierHelpTextId = 0;
            StatusMode status = getStatusForIccState(simState);
            switch (status) {
                case PersoLocked:
                    carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled;
                    break;

                case SimMissing:
                    carrierHelpTextId = R.string.lockscreen_missing_sim_instructions_long;
                    break;

                case SimPermDisabled:
                    carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions;
                    break;

                case SimMissingLocked:
                    carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
                    break;

                case Normal:
                case SimLocked:
                case SimPukLocked:
                    break;
            }

            return mContext.getText(carrierHelpTextId);
        }
    上述加粗标红的代码就是我们需要作出修改的位置。












  • 相关阅读:
    生产环境常见的几种JVM异常
    JVM垃圾回收时如何确定垃圾?是否知道什么是GCRoots?
    你平时工作用过的JVM常用基本配置参数有哪些?
    java X参数
    JUC之CAS
    JUC之List集合
    JUC之lock
    JUC之volatile
    BZOJ2132: 圈地计划
    BZOJ3991: [SDOI2015]寻宝游戏
  • 原文地址:https://www.cnblogs.com/bill-technology/p/4130838.html
Copyright © 2011-2022 走看看