解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复

解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复

从图片中我们可以看到,这里在语义上有一定的重复,当然这是谷歌的原始设计。这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,不过由于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);

    }

上述加粗标红的代码就是我们需要作出修改的位置。

上一篇:easyui实现背景图片半透明状态,悬浮在大背景之上


下一篇:【转】Qt事件循环与线程 二