Added Emergency affordance feature am: 705442fa7d
am: 0e1f78da65
Change-Id: I6f8220b18bce7889e3b9efe1b075a680a0ae7187
This commit is contained in:
@@ -44,7 +44,6 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.DropBoxManager;
|
import android.os.DropBoxManager;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -8371,6 +8370,13 @@ public final class Settings {
|
|||||||
*/
|
*/
|
||||||
public static final String CALL_AUTO_RETRY = "call_auto_retry";
|
public static final String CALL_AUTO_RETRY = "call_auto_retry";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A setting that can be read whether the emergency affordance is currently needed.
|
||||||
|
* The value is a boolean (1 or 0).
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See RIL_PreferredNetworkType in ril.h
|
* See RIL_PreferredNetworkType in ril.h
|
||||||
* @hide
|
* @hide
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.policy;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that manages emergency affordances and enables immediate calling to emergency services
|
||||||
|
*/
|
||||||
|
public class EmergencyAffordanceManager {
|
||||||
|
|
||||||
|
public static final boolean ENABLED = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global setting override with the number to call with the emergency affordance.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private static final String EMERGENCY_CALL_NUMBER_SETTING = "emergency_affordance_number";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global setting, whether the emergency affordance should be shown regardless of device state.
|
||||||
|
* The value is a boolean (1 or 0).
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private static final String FORCE_EMERGENCY_AFFORDANCE_SETTING = "force_emergency_affordance";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public EmergencyAffordanceManager(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* perform an emergency call.
|
||||||
|
*/
|
||||||
|
public final void performEmergencyCall() {
|
||||||
|
performEmergencyCall(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri getPhoneUri(Context context) {
|
||||||
|
String number = context.getResources().getString(
|
||||||
|
com.android.internal.R.string.config_emergency_call_number);
|
||||||
|
if (Build.IS_DEBUGGABLE) {
|
||||||
|
String override = Settings.Global.getString(
|
||||||
|
context.getContentResolver(), EMERGENCY_CALL_NUMBER_SETTING);
|
||||||
|
if (override != null) {
|
||||||
|
number = override;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Uri.fromParts("tel", number, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void performEmergencyCall(Context context) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
|
||||||
|
intent.setData(getPhoneUri(context));
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether emergency affordance should be active.
|
||||||
|
*/
|
||||||
|
public boolean needsEmergencyAffordance() {
|
||||||
|
if (!ENABLED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (forceShowing()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return isEmergencyAffordanceNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmergencyAffordanceNeeded() {
|
||||||
|
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean forceShowing() {
|
||||||
|
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
|
FORCE_EMERGENCY_AFFORDANCE_SETTING, 0) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
core/res/res/drawable/emergency_icon.xml
Normal file
40
core/res/res/drawable/emergency_icon.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2014 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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24.0dp"
|
||||||
|
android:height="24.0dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M6.8,17.3C5.3,15.9 4.5,14.0 4.5,12.0c0.0,-2.0 0.8,-3.8 2.1,-5.2l1.4,1.4c-1.0,1.0 -1.6,2.4 -1.6,3.8c0.0,1.5 0.6,2.9 1.6,3.9L6.8,17.3z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M3.3,20.2C1.2,18.0 0.0,15.1 0.0,12.0c0.0,-3.1 1.2,-6.0 3.3,-8.2l1.4,1.4C3.0,7.0 2.0,9.4 2.0,12.0s1.0,5.0 2.7,6.9L3.3,20.2z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M17.2,17.3l-1.4,-1.4c1.1,-1.0 1.6,-2.4 1.6,-3.9c0.0,-1.4 -0.6,-2.8 -1.6,-3.8l1.4,-1.4c1.4,1.4 2.1,3.3 2.1,5.2C19.5,14.0 18.7,15.9 17.2,17.3z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M20.7,20.2l-1.4,-1.4C21.0,17.0 22.0,14.6 22.0,12.0c0.0,-2.6 -1.0,-5.0 -2.7,-6.9l1.4,-1.4C22.8,6.0 24.0,8.9 24.0,12.0C24.0,15.1 22.8,18.0 20.7,20.2z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M11.0,15.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M11.0,7.0l2.0,0.0l0.0,6.0l-2.0,0.0z"/>
|
||||||
|
</vector>
|
||||||
@@ -2576,6 +2576,16 @@
|
|||||||
<!-- True if the device supports system navigation keys. -->
|
<!-- True if the device supports system navigation keys. -->
|
||||||
<bool name="config_supportSystemNavigationKeys">false</bool>
|
<bool name="config_supportSystemNavigationKeys">false</bool>
|
||||||
|
|
||||||
|
<!-- emergency call number for the emergency affordance -->
|
||||||
|
<string name="config_emergency_call_number" translatable="false">112</string>
|
||||||
|
|
||||||
|
<!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
|
||||||
|
affordances-->
|
||||||
|
<integer-array name="config_emergency_mcc_codes" translatable="false">
|
||||||
|
<item>404</item>
|
||||||
|
<item>405</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
<!-- Package name for the device provisioning package. -->
|
<!-- Package name for the device provisioning package. -->
|
||||||
<string name="config_deviceProvisioningPackage"></string>
|
<string name="config_deviceProvisioningPackage"></string>
|
||||||
|
|
||||||
|
|||||||
@@ -486,6 +486,9 @@
|
|||||||
<!-- TODO: promote to separate string-->
|
<!-- TODO: promote to separate string-->
|
||||||
<string name="global_action_restart" translatable="false">@string/sim_restart_button</string>
|
<string name="global_action_restart" translatable="false">@string/sim_restart_button</string>
|
||||||
|
|
||||||
|
<!-- label for item that starts emergency call -->
|
||||||
|
<string name="global_action_emergency">Emergency</string>
|
||||||
|
|
||||||
<!-- label for item that generates a bug report in the phone options dialog -->
|
<!-- label for item that generates a bug report in the phone options dialog -->
|
||||||
<string name="global_action_bug_report">Bug report</string>
|
<string name="global_action_bug_report">Bug report</string>
|
||||||
|
|
||||||
|
|||||||
@@ -2673,6 +2673,10 @@
|
|||||||
|
|
||||||
<java-symbol type="string" name="lockscreen_storage_locked" />
|
<java-symbol type="string" name="lockscreen_storage_locked" />
|
||||||
|
|
||||||
|
<java-symbol type="string" name="global_action_emergency" />
|
||||||
|
<java-symbol type="string" name="config_emergency_call_number" />
|
||||||
|
<java-symbol type="array" name="config_emergency_mcc_codes" />
|
||||||
|
|
||||||
<!-- Used for MimeIconUtils. -->
|
<!-- Used for MimeIconUtils. -->
|
||||||
<java-symbol type="drawable" name="ic_doc_apk" />
|
<java-symbol type="drawable" name="ic_doc_apk" />
|
||||||
<java-symbol type="drawable" name="ic_doc_audio" />
|
<java-symbol type="drawable" name="ic_doc_audio" />
|
||||||
@@ -2709,6 +2713,8 @@
|
|||||||
|
|
||||||
<java-symbol type="drawable" name="ic_restart" />
|
<java-symbol type="drawable" name="ic_restart" />
|
||||||
|
|
||||||
|
<java-symbol type="drawable" name="emergency_icon" />
|
||||||
|
|
||||||
<java-symbol type="array" name="config_convert_to_emergency_number_map" />
|
<java-symbol type="array" name="config_convert_to_emergency_number_map" />
|
||||||
|
|
||||||
<java-symbol type="array" name="config_nonBlockableNotificationPackages" />
|
<java-symbol type="array" name="config_nonBlockableNotificationPackages" />
|
||||||
|
|||||||
@@ -28,13 +28,16 @@ import android.os.UserHandle;
|
|||||||
import android.telecom.TelecomManager;
|
import android.telecom.TelecomManager;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.telephony.IccCardConstants.State;
|
import com.android.internal.telephony.IccCardConstants.State;
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
|
import com.android.internal.policy.EmergencyAffordanceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements a smart emergency button that updates itself based
|
* This class implements a smart emergency button that updates itself based
|
||||||
@@ -51,7 +54,10 @@ public class EmergencyButton extends Button {
|
|||||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
|
||||||
private static final String LOG_TAG = "EmergencyButton";
|
private static final String LOG_TAG = "EmergencyButton";
|
||||||
|
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
|
||||||
|
|
||||||
|
private int mDownX;
|
||||||
|
private int mDownY;
|
||||||
KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
|
KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,6 +70,7 @@ public class EmergencyButton extends Button {
|
|||||||
updateEmergencyCallButton();
|
updateEmergencyCallButton();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private boolean mLongPressWasDragged;
|
||||||
|
|
||||||
public interface EmergencyButtonCallback {
|
public interface EmergencyButtonCallback {
|
||||||
public void onEmergencyButtonClickedWhenInCall();
|
public void onEmergencyButtonClickedWhenInCall();
|
||||||
@@ -86,6 +93,7 @@ public class EmergencyButton extends Button {
|
|||||||
com.android.internal.R.bool.config_voice_capable);
|
com.android.internal.R.bool.config_voice_capable);
|
||||||
mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
|
mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
|
||||||
com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
|
com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
|
||||||
|
mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -110,9 +118,44 @@ public class EmergencyButton extends Button {
|
|||||||
takeEmergencyCallAction();
|
takeEmergencyCallAction();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setOnLongClickListener(new OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
if (!mLongPressWasDragged
|
||||||
|
&& mEmergencyAffordanceManager.needsEmergencyAffordance()) {
|
||||||
|
mEmergencyAffordanceManager.performEmergencyCall();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
updateEmergencyCallButton();
|
updateEmergencyCallButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
final int x = (int) event.getX();
|
||||||
|
final int y = (int) event.getY();
|
||||||
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
|
mDownX = x;
|
||||||
|
mDownY = y;
|
||||||
|
mLongPressWasDragged = false;
|
||||||
|
} else {
|
||||||
|
final int xDiff = Math.abs(x - mDownX);
|
||||||
|
final int yDiff = Math.abs(y - mDownY);
|
||||||
|
int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
|
||||||
|
if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
|
||||||
|
mLongPressWasDragged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performLongClick() {
|
||||||
|
return super.performLongClick();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onConfigurationChanged(Configuration newConfig) {
|
protected void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
|
|||||||
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.emergency;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.telephony.CellInfo;
|
||||||
|
import android.telephony.CellInfoGsm;
|
||||||
|
import android.telephony.CellInfoLte;
|
||||||
|
import android.telephony.CellInfoWcdma;
|
||||||
|
import android.telephony.CellLocation;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.SubscriptionInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
import com.android.server.SystemService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that listens to connectivity and SIM card changes and determines if the emergency mode
|
||||||
|
* should be enabled
|
||||||
|
*/
|
||||||
|
public class EmergencyAffordanceService extends SystemService {
|
||||||
|
|
||||||
|
private static final String TAG = "EmergencyAffordanceService";
|
||||||
|
|
||||||
|
private static final int NUM_SCANS_UNTIL_ABORT = 4;
|
||||||
|
|
||||||
|
private static final int INITIALIZE_STATE = 1;
|
||||||
|
private static final int CELL_INFO_STATE_CHANGED = 2;
|
||||||
|
private static final int SUBSCRIPTION_CHANGED = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
|
||||||
|
* requires the emergency affordance. The value is a boolean (1 or 0).
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final ArrayList<Integer> mEmergencyCallMccNumbers;
|
||||||
|
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
|
private TelephonyManager mTelephonyManager;
|
||||||
|
private SubscriptionManager mSubscriptionManager;
|
||||||
|
private boolean mEmergencyAffordanceNeeded;
|
||||||
|
private MyHandler mHandler;
|
||||||
|
private int mScansCompleted;
|
||||||
|
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onCellInfoChanged(List<CellInfo> cellInfo) {
|
||||||
|
if (!isEmergencyAffordanceNeeded()) {
|
||||||
|
requestCellScan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCellLocationChanged(CellLocation location) {
|
||||||
|
if (!isEmergencyAffordanceNeeded()) {
|
||||||
|
requestCellScan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (Settings.Global.getInt(context.getContentResolver(),
|
||||||
|
Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
|
||||||
|
startScanning();
|
||||||
|
requestCellScan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private boolean mSimNeedsEmergencyAffordance;
|
||||||
|
private boolean mNetworkNeedsEmergencyAffordance;
|
||||||
|
|
||||||
|
private void requestCellScan() {
|
||||||
|
mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
|
||||||
|
= new SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||||
|
@Override
|
||||||
|
public void onSubscriptionsChanged() {
|
||||||
|
mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public EmergencyAffordanceService(Context context) {
|
||||||
|
super(context);
|
||||||
|
mContext = context;
|
||||||
|
int[] numbers = context.getResources().getIntArray(
|
||||||
|
com.android.internal.R.array.config_emergency_mcc_codes);
|
||||||
|
mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
|
||||||
|
for (int i = 0; i < numbers.length; i++) {
|
||||||
|
mEmergencyCallMccNumbers.add(numbers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateEmergencyAffordanceNeeded() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mEmergencyAffordanceNeeded = mSimNeedsEmergencyAffordance ||
|
||||||
|
mNetworkNeedsEmergencyAffordance;
|
||||||
|
Settings.Global.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
|
||||||
|
mEmergencyAffordanceNeeded ? 1 : 0);
|
||||||
|
if (mEmergencyAffordanceNeeded) {
|
||||||
|
stopScanning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopScanning() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||||
|
mScansCompleted = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmergencyAffordanceNeeded() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
return mEmergencyAffordanceNeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBootPhase(int phase) {
|
||||||
|
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||||
|
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||||
|
mSubscriptionManager = SubscriptionManager.from(mContext);
|
||||||
|
HandlerThread thread = new HandlerThread(TAG);
|
||||||
|
thread.start();
|
||||||
|
mHandler = new MyHandler(thread.getLooper());
|
||||||
|
mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
|
||||||
|
startScanning();
|
||||||
|
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||||
|
mContext.registerReceiver(mAirplaneModeReceiver, filter);
|
||||||
|
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startScanning() {
|
||||||
|
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
|
||||||
|
| PhoneStateListener.LISTEN_CELL_LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handler to do the heavier work on */
|
||||||
|
private class MyHandler extends Handler {
|
||||||
|
|
||||||
|
public MyHandler(Looper l) {
|
||||||
|
super(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case INITIALIZE_STATE:
|
||||||
|
handleInitializeState();
|
||||||
|
break;
|
||||||
|
case CELL_INFO_STATE_CHANGED:
|
||||||
|
handleUpdateCellInfo();
|
||||||
|
break;
|
||||||
|
case SUBSCRIPTION_CHANGED:
|
||||||
|
handleUpdateSimSubscriptionInfo();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleInitializeState() {
|
||||||
|
if (handleUpdateSimSubscriptionInfo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (handleUpdateCellInfo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateEmergencyAffordanceNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleUpdateSimSubscriptionInfo() {
|
||||||
|
boolean neededBefore = simNeededAffordanceBefore();
|
||||||
|
boolean neededNow = neededBefore;
|
||||||
|
List<SubscriptionInfo> activeSubscriptionInfoList =
|
||||||
|
mSubscriptionManager.getActiveSubscriptionInfoList();
|
||||||
|
if (activeSubscriptionInfoList == null) {
|
||||||
|
return neededNow;
|
||||||
|
}
|
||||||
|
for (SubscriptionInfo info : activeSubscriptionInfoList) {
|
||||||
|
int mcc = info.getMcc();
|
||||||
|
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||||
|
neededNow = true;
|
||||||
|
break;
|
||||||
|
} else if (mcc != 0 && mcc != Integer.MAX_VALUE){
|
||||||
|
// a Sim with a different mcc code was found
|
||||||
|
neededNow = false;
|
||||||
|
}
|
||||||
|
String simOperator = mTelephonyManager.getSimOperator(info.getSubscriptionId());
|
||||||
|
mcc = 0;
|
||||||
|
if (simOperator != null && simOperator.length() >= 3) {
|
||||||
|
mcc = Integer.parseInt(simOperator.substring(0, 3));
|
||||||
|
}
|
||||||
|
if (mcc != 0) {
|
||||||
|
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||||
|
neededNow = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// a Sim with a different mcc code was found
|
||||||
|
neededNow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (neededNow != neededBefore) {
|
||||||
|
setSimNeedsEmergencyAffordance(neededNow);
|
||||||
|
}
|
||||||
|
return neededNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
|
||||||
|
mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
|
||||||
|
Settings.Global.putInt(mContext.getContentResolver(),
|
||||||
|
EMERGENCY_SIM_INSERTED_SETTING,
|
||||||
|
simNeedsEmergencyAffordance ? 1 : 0);
|
||||||
|
updateEmergencyAffordanceNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean simNeededAffordanceBefore() {
|
||||||
|
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
|
"emergency_sim_inserted_before", 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleUpdateCellInfo() {
|
||||||
|
List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
|
||||||
|
if (cellInfos == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean stopScanningAfterScan = false;
|
||||||
|
for (CellInfo cellInfo : cellInfos) {
|
||||||
|
int mcc = 0;
|
||||||
|
if (cellInfo instanceof CellInfoGsm) {
|
||||||
|
mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
|
||||||
|
} else if (cellInfo instanceof CellInfoLte) {
|
||||||
|
mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
|
||||||
|
} else if (cellInfo instanceof CellInfoWcdma) {
|
||||||
|
mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
|
||||||
|
}
|
||||||
|
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||||
|
setNetworkNeedsEmergencyAffordance(true);
|
||||||
|
return true;
|
||||||
|
} else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
|
||||||
|
// we found an mcc that isn't in the list, abort
|
||||||
|
stopScanningAfterScan = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stopScanningAfterScan) {
|
||||||
|
stopScanning();
|
||||||
|
} else {
|
||||||
|
onCellScanFinishedUnsuccessful();
|
||||||
|
}
|
||||||
|
setNetworkNeedsEmergencyAffordance(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mNetworkNeedsEmergencyAffordance = needsAffordance;
|
||||||
|
updateEmergencyAffordanceNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCellScanFinishedUnsuccessful() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mScansCompleted++;
|
||||||
|
if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
|
||||||
|
stopScanning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mccRequiresEmergencyAffordance(int mcc) {
|
||||||
|
return mEmergencyCallMccNumbers.contains(mcc);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import com.android.internal.app.AlertController;
|
|||||||
import com.android.internal.app.AlertController.AlertParams;
|
import com.android.internal.app.AlertController.AlertParams;
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.internal.policy.EmergencyAffordanceManager;
|
||||||
import com.android.internal.telephony.TelephonyIntents;
|
import com.android.internal.telephony.TelephonyIntents;
|
||||||
import com.android.internal.telephony.TelephonyProperties;
|
import com.android.internal.telephony.TelephonyProperties;
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
@@ -27,7 +28,6 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -125,6 +125,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
|||||||
private boolean mHasTelephony;
|
private boolean mHasTelephony;
|
||||||
private boolean mHasVibrator;
|
private boolean mHasVibrator;
|
||||||
private final boolean mShowSilentToggle;
|
private final boolean mShowSilentToggle;
|
||||||
|
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context everything needs a context :(
|
* @param context everything needs a context :(
|
||||||
@@ -159,6 +160,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
|||||||
|
|
||||||
mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
|
mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
|
||||||
com.android.internal.R.bool.config_useFixedVolume);
|
com.android.internal.R.bool.config_useFixedVolume);
|
||||||
|
|
||||||
|
mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,6 +311,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
|||||||
addedKeys.add(actionKey);
|
addedKeys.add(actionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
|
||||||
|
mItems.add(getEmergencyAction());
|
||||||
|
}
|
||||||
|
|
||||||
mAdapter = new MyAdapter();
|
mAdapter = new MyAdapter();
|
||||||
|
|
||||||
AlertParams params = new AlertParams(mContext);
|
AlertParams params = new AlertParams(mContext);
|
||||||
@@ -493,6 +500,26 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Action getEmergencyAction() {
|
||||||
|
return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
|
||||||
|
R.string.global_action_emergency) {
|
||||||
|
@Override
|
||||||
|
public void onPress() {
|
||||||
|
mEmergencyAffordanceManager.performEmergencyCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showDuringKeyguard() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showBeforeProvisioning() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private Action getAssistAction() {
|
private Action getAssistAction() {
|
||||||
return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
|
return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
|
||||||
R.string.global_action_assist) {
|
R.string.global_action_assist) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.server;
|
package com.android.server;
|
||||||
|
|
||||||
import android.app.ActivityManagerNative;
|
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
@@ -32,7 +31,6 @@ import android.os.Build;
|
|||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.FactoryTest;
|
import android.os.FactoryTest;
|
||||||
import android.os.FileUtils;
|
import android.os.FileUtils;
|
||||||
import android.os.IPowerManager;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -55,6 +53,7 @@ import com.android.internal.app.NightDisplayController;
|
|||||||
import com.android.internal.os.BinderInternal;
|
import com.android.internal.os.BinderInternal;
|
||||||
import com.android.internal.os.SamplingProfilerIntegration;
|
import com.android.internal.os.SamplingProfilerIntegration;
|
||||||
import com.android.internal.os.ZygoteInit;
|
import com.android.internal.os.ZygoteInit;
|
||||||
|
import com.android.internal.policy.EmergencyAffordanceManager;
|
||||||
import com.android.internal.widget.ILockSettings;
|
import com.android.internal.widget.ILockSettings;
|
||||||
import com.android.server.accessibility.AccessibilityManagerService;
|
import com.android.server.accessibility.AccessibilityManagerService;
|
||||||
import com.android.server.am.ActivityManagerService;
|
import com.android.server.am.ActivityManagerService;
|
||||||
@@ -67,6 +66,7 @@ import com.android.server.devicepolicy.DevicePolicyManagerService;
|
|||||||
import com.android.server.display.DisplayManagerService;
|
import com.android.server.display.DisplayManagerService;
|
||||||
import com.android.server.display.NightDisplayService;
|
import com.android.server.display.NightDisplayService;
|
||||||
import com.android.server.dreams.DreamManagerService;
|
import com.android.server.dreams.DreamManagerService;
|
||||||
|
import com.android.server.emergency.EmergencyAffordanceService;
|
||||||
import com.android.server.fingerprint.FingerprintService;
|
import com.android.server.fingerprint.FingerprintService;
|
||||||
import com.android.server.hdmi.HdmiControlService;
|
import com.android.server.hdmi.HdmiControlService;
|
||||||
import com.android.server.input.InputManagerService;
|
import com.android.server.input.InputManagerService;
|
||||||
@@ -1097,6 +1097,11 @@ public final class SystemServer {
|
|||||||
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
|
||||||
|
// EmergencyMode sevice
|
||||||
|
mSystemServiceManager.startService(EmergencyAffordanceService.class);
|
||||||
|
}
|
||||||
|
|
||||||
if (!disableNonCoreServices) {
|
if (!disableNonCoreServices) {
|
||||||
// Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
|
// Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
|
||||||
mSystemServiceManager.startService(DreamManagerService.class);
|
mSystemServiceManager.startService(DreamManagerService.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user