OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / emergency / EmergencyAffordanceService.java
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17 package com.android.server.emergency;
18
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.provider.Settings;
28 import android.telephony.CellInfo;
29 import android.telephony.CellInfoGsm;
30 import android.telephony.CellInfoLte;
31 import android.telephony.CellInfoWcdma;
32 import android.telephony.CellLocation;
33 import android.telephony.PhoneStateListener;
34 import android.telephony.SubscriptionInfo;
35 import android.telephony.SubscriptionManager;
36 import android.telephony.TelephonyManager;
37
38 import com.android.server.SystemService;
39
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.List;
43
44 /**
45  * A service that listens to connectivity and SIM card changes and determines if the emergency mode
46  * should be enabled
47  */
48 public class EmergencyAffordanceService extends SystemService {
49
50     private static final String TAG = "EmergencyAffordanceService";
51
52     private static final int NUM_SCANS_UNTIL_ABORT = 4;
53
54     private static final int INITIALIZE_STATE = 1;
55     private static final int CELL_INFO_STATE_CHANGED = 2;
56     private static final int SUBSCRIPTION_CHANGED = 3;
57
58     /**
59      * Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
60      * requires the emergency affordance. The value is a boolean (1 or 0).
61      * @hide
62      */
63     private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
64
65     private final Context mContext;
66     private final ArrayList<Integer> mEmergencyCallMccNumbers;
67
68     private final Object mLock = new Object();
69
70     private TelephonyManager mTelephonyManager;
71     private SubscriptionManager mSubscriptionManager;
72     private boolean mEmergencyAffordanceNeeded;
73     private MyHandler mHandler;
74     private int mScansCompleted;
75     private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
76         @Override
77         public void onCellInfoChanged(List<CellInfo> cellInfo) {
78             if (!isEmergencyAffordanceNeeded()) {
79                 requestCellScan();
80             }
81         }
82
83         @Override
84         public void onCellLocationChanged(CellLocation location) {
85             if (!isEmergencyAffordanceNeeded()) {
86                 requestCellScan();
87             }
88         }
89     };
90     private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
91         @Override
92         public void onReceive(Context context, Intent intent) {
93             if (Settings.Global.getInt(context.getContentResolver(),
94                     Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
95                 startScanning();
96                 requestCellScan();
97             }
98         }
99     };
100     private boolean mSimNeedsEmergencyAffordance;
101     private boolean mNetworkNeedsEmergencyAffordance;
102     private boolean mVoiceCapable;
103
104     private void requestCellScan() {
105         mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
106     }
107
108     private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
109             = new SubscriptionManager.OnSubscriptionsChangedListener() {
110         @Override
111         public void onSubscriptionsChanged() {
112             mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
113         }
114     };
115
116     public EmergencyAffordanceService(Context context) {
117         super(context);
118         mContext = context;
119         int[] numbers = context.getResources().getIntArray(
120                 com.android.internal.R.array.config_emergency_mcc_codes);
121         mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
122         for (int i = 0; i < numbers.length; i++) {
123             mEmergencyCallMccNumbers.add(numbers[i]);
124         }
125     }
126
127     private void updateEmergencyAffordanceNeeded() {
128         synchronized (mLock) {
129             mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
130                     mNetworkNeedsEmergencyAffordance);
131             Settings.Global.putInt(mContext.getContentResolver(),
132                     Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
133                     mEmergencyAffordanceNeeded ? 1 : 0);
134             if (mEmergencyAffordanceNeeded) {
135                 stopScanning();
136             }
137         }
138     }
139
140     private void stopScanning() {
141         synchronized (mLock) {
142             mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
143             mScansCompleted = 0;
144         }
145     }
146
147     private boolean isEmergencyAffordanceNeeded() {
148         synchronized (mLock) {
149             return mEmergencyAffordanceNeeded;
150         }
151     }
152
153     @Override
154     public void onStart() {
155     }
156
157     @Override
158     public void onBootPhase(int phase) {
159         if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
160             mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
161             mVoiceCapable = mTelephonyManager.isVoiceCapable();
162             if (!mVoiceCapable) {
163                 updateEmergencyAffordanceNeeded();
164                 return;
165             }
166             mSubscriptionManager = SubscriptionManager.from(mContext);
167             HandlerThread thread = new HandlerThread(TAG);
168             thread.start();
169             mHandler = new MyHandler(thread.getLooper());
170             mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
171             startScanning();
172             IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
173             mContext.registerReceiver(mAirplaneModeReceiver, filter);
174             mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
175         }
176     }
177
178     private void startScanning() {
179         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
180                 | PhoneStateListener.LISTEN_CELL_LOCATION);
181     }
182
183     /** Handler to do the heavier work on */
184     private class MyHandler extends Handler {
185
186         public MyHandler(Looper l) {
187             super(l);
188         }
189
190         @Override
191         public void handleMessage(Message msg) {
192             switch (msg.what) {
193                 case INITIALIZE_STATE:
194                     handleInitializeState();
195                     break;
196                 case CELL_INFO_STATE_CHANGED:
197                     handleUpdateCellInfo();
198                     break;
199                 case SUBSCRIPTION_CHANGED:
200                     handleUpdateSimSubscriptionInfo();
201                     break;
202             }
203         }
204     }
205
206     private void handleInitializeState() {
207         if (handleUpdateSimSubscriptionInfo()) {
208             return;
209         }
210         if (handleUpdateCellInfo()) {
211             return;
212         }
213         updateEmergencyAffordanceNeeded();
214     }
215
216     private boolean handleUpdateSimSubscriptionInfo() {
217         boolean neededBefore = simNeededAffordanceBefore();
218         boolean neededNow = neededBefore;
219         List<SubscriptionInfo> activeSubscriptionInfoList =
220                 mSubscriptionManager.getActiveSubscriptionInfoList();
221         if (activeSubscriptionInfoList == null) {
222             return neededNow;
223         }
224         for (SubscriptionInfo info : activeSubscriptionInfoList) {
225             int mcc = info.getMcc();
226             if (mccRequiresEmergencyAffordance(mcc)) {
227                 neededNow = true;
228                 break;
229             } else if (mcc != 0 && mcc != Integer.MAX_VALUE){
230                 // a Sim with a different mcc code was found
231                 neededNow = false;
232             }
233             String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
234             mcc = 0;
235             if (simOperator != null && simOperator.length() >= 3) {
236                 mcc = Integer.parseInt(simOperator.substring(0, 3));
237             }
238             if (mcc != 0) {
239                 if (mccRequiresEmergencyAffordance(mcc)) {
240                     neededNow = true;
241                     break;
242                 } else {
243                     // a Sim with a different mcc code was found
244                     neededNow = false;
245                 }
246             }
247         }
248         if (neededNow != neededBefore) {
249             setSimNeedsEmergencyAffordance(neededNow);
250         }
251         return neededNow;
252     }
253
254     private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
255         mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
256         Settings.Global.putInt(mContext.getContentResolver(),
257                 EMERGENCY_SIM_INSERTED_SETTING,
258                 simNeedsEmergencyAffordance ? 1 : 0);
259         updateEmergencyAffordanceNeeded();
260     }
261
262     private boolean simNeededAffordanceBefore() {
263         return Settings.Global.getInt(mContext.getContentResolver(),
264                 "emergency_sim_inserted_before", 0) != 0;
265     }
266
267     private boolean handleUpdateCellInfo() {
268         List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
269         if (cellInfos == null) {
270             return false;
271         }
272         boolean stopScanningAfterScan = false;
273         for (CellInfo cellInfo : cellInfos) {
274             int mcc = 0;
275             if (cellInfo instanceof CellInfoGsm) {
276                 mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
277             } else if (cellInfo instanceof CellInfoLte) {
278                 mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
279             } else if (cellInfo instanceof CellInfoWcdma) {
280                 mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
281             }
282             if (mccRequiresEmergencyAffordance(mcc)) {
283                 setNetworkNeedsEmergencyAffordance(true);
284                 return true;
285             } else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
286                 // we found an mcc that isn't in the list, abort
287                 stopScanningAfterScan = true;
288             }
289         }
290         if (stopScanningAfterScan) {
291             stopScanning();
292         } else {
293             onCellScanFinishedUnsuccessful();
294         }
295         setNetworkNeedsEmergencyAffordance(false);
296         return false;
297     }
298
299     private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
300         synchronized (mLock) {
301             mNetworkNeedsEmergencyAffordance = needsAffordance;
302             updateEmergencyAffordanceNeeded();
303         }
304     }
305
306     private void onCellScanFinishedUnsuccessful() {
307         synchronized (mLock) {
308             mScansCompleted++;
309             if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
310                 stopScanning();
311             }
312         }
313     }
314
315     private boolean mccRequiresEmergencyAffordance(int mcc) {
316         return mEmergencyCallMccNumbers.contains(mcc);
317     }
318 }