解决: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即使我们须要改动的锁屏界面下的紧急拨号button所相应的布局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);

}

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

时间: 2024-10-18 03:53:56

解决: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</s

Android4.0+锁屏程序开发——设置锁屏页面篇

[如何开发一个锁屏应用] 想要开发一个锁屏应用,似乎很难,其实并没有想象中那么难. 从本质上来说,锁屏界面也只是一个Activity而已,只是这个界面比较特殊,在我们点亮屏幕的时候,这个界面就会出现. 而且在此界面中,我们可以用一些行为来退出,比如点击按钮等. 还有一个特征是在这个界面的时候,我们通常是不能使用底部的三个按钮的 关于如果屏蔽底部的三个按钮,我已经在另一篇博客Android4.0+锁屏程序开发——按键屏蔽篇进行了总结,有需要的朋友可以参看. 这篇博客我们主要讨论如何让一个Activ

Android5.1 - 锁屏界面时间显示

[问题]待机唤醒解锁界面时间显示不全.不论是8寸还是7寸的屏幕都有此问题.时间显示设置为“上午10:30”的时候,最右边的数字0残缺.而时间数字少于4个时,数字不会残缺. [debug]找到相关的配置文件,把文字的大小修改为合适的值即可.在frameworks/base/packages下有2个目录,分别是Keyguard和SystemUI. 查看SystemUI的Android.mk文件LOCAL_STATIC_JAVA_LIBRARIES := Keyguard android-suppor

iOS开发--QQ音乐练习,后台播放和锁屏界面

一.设置后台播放 首先允许程序后台播放 代码实现 1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 2 3 // 设置后台播放的代码,步骤 4 // 1.获取音频的会话 5 AVAudioSession *session = [AVAudioSession sharedInstance]; 6 // 2.设置后台播放类型

Android4.0+锁屏程序开发——按键屏蔽篇

开发锁屏程序的时候我们要面临的重要问题无疑是如何屏蔽三个按键,Back,Home,Menu  看似简单的功能,实现起来却并不是那么容易. [屏蔽Back按键] 相对来说,屏蔽Back键是比较简单的,只需要在我们的Activity中重写onKeyDown方法,并在其中对Back按键进行拦截即可,代码如下 //屏蔽back @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case

Android 7.1.1 锁屏界面启动流程

前几天遇到一个低概率复现锁屏界面不显示,仅仅显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看.前面简介了下Zygote启动流程, Zygote进程启动后会首先创建一个SystemServer进程,SystemServer进程在调用startOtherServices同一时候也会调用WindowManagerService的systemReady()方法 //frameworks/base/services/java/com/android/server/System

win10如何移除锁屏界面网络图标

在Win10的锁屏界面,右下角默认会有网络图标,用于指示当前网络状态.如果你感觉这个图标碍眼,可以使用win10专业版官网的方法把它移除.需要注意的是,在这里移除后,里面的登录界面网络图标也会消失,那个图标点击后可以进行连接操作. 具体方法如下: 1.在Cortana搜索栏输入澳门银河娱乐场,按回车键进入注册表编辑器 2.定位到 HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System 3.新建DWORD(32位)值,命名为Don

android解锁界面,插上USB弹出打开USB存储设置界面,按HOME键/返回键直接回到launcher,而非滑动锁屏界面

1)如果将setting-->开发者选项-->USB调试  disable掉,表示当前是用户模式,锁屏界面下插上USB,AMS就会叫起UsbStorageActivity"打开USB存储设备"这个界面. 2)UsbStorageActivity界面在onCreate()中设置了如下属性: getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); if (Environment.isExte

iOS开发——实用技术精选OC篇&amp;后台音乐与锁屏界面音乐播放

一:后台音乐播放 在plist中开启后台服务 实现简单的代码 二:锁屏界面音乐播放 其他按钮的实现(上一曲,下一曲,暂停,播放) 最后将歌词实时的绘制上去: