├── README.md ├── Android.mk └── src └── com └── qualcomm └── qti └── internal └── telephony ├── QtiTelephonyComponentFactory.java └── ArrowExtTelephony.java /README.md: -------------------------------------------------------------------------------- 1 | qti-telephony-common 2 | ==================== 3 | 4 | Including this jar 5 | ------------------ 6 | To include this jar in your builds, you must add qti-telephony-common to PRODUCT_PACKAGES and add telephony-ext to PRODUCT_BOOT_JARS. For devices not using qcom sepolicy, extphone must be labelled as u:object_r:radio_service:s0 in the device's private platform selinux service contexts. 7 | 8 | Avoiding this jar 9 | ----------------- 10 | If a device provides its own qti-telephony-common target, either by extending this with more device specific extensions or setting up the proprietary one as a target, the device must set TARGET_PROVIDES_QTI_TELEPHONY_JAR to true. 11 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 The LineageOS 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 | LOCAL_PATH := $(call my-dir) 18 | 19 | ifeq ($(TARGET_PROVIDES_QTI_TELEPHONY_JAR),) 20 | include $(CLEAR_VARS) 21 | LOCAL_MODULE := qti-telephony-common 22 | LOCAL_JAVA_LIBRARIES := telephony-common telephony-ext 23 | LOCAL_REQUIRED_MODULES := telephony-ext 24 | LOCAL_SRC_FILES := $(call all-java-files-under,src) 25 | LOCAL_MODULE_TAGS := optional 26 | LOCAL_DEX_PREOPT := false 27 | include $(BUILD_JAVA_LIBRARY) 28 | endif 29 | -------------------------------------------------------------------------------- /src/com/qualcomm/qti/internal/telephony/QtiTelephonyComponentFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The LineageOS 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.qualcomm.qti.internal.telephony; 18 | 19 | import android.content.Context; 20 | import android.telephony.Rlog; 21 | 22 | import com.android.internal.telephony.CommandsInterface; 23 | import com.android.internal.telephony.Phone; 24 | import com.android.internal.telephony.TelephonyComponentFactory; 25 | 26 | import com.qualcomm.qti.internal.telephony.ArrowExtTelephony; 27 | 28 | public class QtiTelephonyComponentFactory extends TelephonyComponentFactory { 29 | 30 | @Override 31 | public void makeExtTelephonyClasses(Context context, 32 | Phone[] phones, CommandsInterface[] commandsInterfaces) { 33 | Rlog.d(LOG_TAG, "makeArrowExtTelephonyClasses"); 34 | try { 35 | ArrowExtTelephony.init(context, phones, commandsInterfaces); 36 | } catch (NoClassDefFoundError e) { 37 | Rlog.e(LOG_TAG, "Error creating ArrowExtTelephony", e); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/qualcomm/qti/internal/telephony/ArrowExtTelephony.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The LineageOS 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.qualcomm.qti.internal.telephony; 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.os.AsyncResult; 22 | import android.os.Handler; 23 | import android.os.Message; 24 | import android.os.ServiceManager; 25 | import android.telecom.PhoneAccount; 26 | import android.telecom.PhoneAccountHandle; 27 | import android.telecom.TelecomManager; 28 | import android.telephony.PhoneNumberUtils; 29 | import android.telephony.SubscriptionManager; 30 | import android.telephony.TelephonyManager; 31 | 32 | import com.android.internal.telephony.CommandsInterface; 33 | import com.android.internal.telephony.Phone; 34 | import com.android.internal.telephony.PhoneConstants; 35 | import com.android.internal.telephony.uicc.IccCardStatus.CardState; 36 | import com.android.internal.telephony.uicc.UiccCard; 37 | import com.android.internal.telephony.uicc.UiccController; 38 | 39 | import org.codeaurora.internal.Client; 40 | import org.codeaurora.internal.IDepersoResCallback; 41 | import org.codeaurora.internal.IDsda; 42 | import org.codeaurora.internal.IExtTelephony; 43 | import org.codeaurora.internal.INetworkCallback; 44 | import org.codeaurora.internal.Token; 45 | 46 | import java.util.Iterator; 47 | 48 | import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 49 | 50 | import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED; 51 | import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED; 52 | 53 | import static android.telephony.TelephonyManager.MultiSimVariants.DSDA; 54 | 55 | import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; 56 | 57 | public class ArrowExtTelephony extends IExtTelephony.Stub { 58 | 59 | class UiccStatus { 60 | 61 | boolean mProvisioned; 62 | int mStatus; 63 | 64 | UiccStatus(int status) { 65 | mProvisioned = true; 66 | mStatus = status; 67 | } 68 | 69 | } 70 | 71 | // Service name 72 | private static final String EXT_TELEPHONY_SERVICE_NAME = "extphone"; 73 | 74 | // Intents (+ extras) to broadcast 75 | private static final String ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED = 76 | "org.codeaurora.intent.action.ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED"; 77 | private static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState"; 78 | 79 | // UICC States 80 | private static final int PROVISIONED = 1; 81 | private static final int NOT_PROVISIONED = 0; 82 | private static final int INVALID_STATE = -1; 83 | private static final int CARD_NOT_PRESENT = -2; 84 | 85 | // Error codes 86 | private static final int SUCCESS = 0; 87 | private static final int GENERIC_FAILURE = -1; 88 | private static final int INVALID_INPUT = -2; 89 | private static final int BUSY = -3; 90 | 91 | // From IccCardProxy.java 92 | private static final int EVENT_ICC_CHANGED = 3; 93 | 94 | private static ArrowExtTelephony sInstance; 95 | 96 | private CommandsInterface[] mCommandsInterfaces; 97 | private Context mContext; 98 | private Handler mHandler; 99 | private Phone[] mPhones; 100 | private SubscriptionManager mSubscriptionManager; 101 | private TelecomManager mTelecomManager; 102 | private TelephonyManager mTelephonyManager; 103 | private UiccController mUiccController; 104 | private UiccStatus mUiccStatus[]; 105 | private boolean mBusy; 106 | 107 | 108 | public static void init(Context context, Phone[] phones, 109 | CommandsInterface[] commandsInterfaces) { 110 | sInstance = getInstance(context, phones, commandsInterfaces); 111 | } 112 | 113 | public static ArrowExtTelephony getInstance(Context context, Phone[] phones, 114 | CommandsInterface[] commandsInterfaces) { 115 | if (sInstance == null) { 116 | sInstance = new ArrowExtTelephony(context, phones, commandsInterfaces); 117 | } 118 | 119 | return sInstance; 120 | } 121 | 122 | private ArrowExtTelephony(Context context, Phone[] phones, 123 | CommandsInterface[] commandsInterfaces) { 124 | if (ServiceManager.getService(EXT_TELEPHONY_SERVICE_NAME) == null) { 125 | ServiceManager.addService(EXT_TELEPHONY_SERVICE_NAME, this); 126 | } 127 | 128 | mCommandsInterfaces = commandsInterfaces; 129 | 130 | mContext = context; 131 | 132 | // Keep track of ICC state changes 133 | mHandler = new Handler() { 134 | @Override 135 | public void handleMessage(Message msg) { 136 | AsyncResult ar; 137 | 138 | if (msg.what == EVENT_ICC_CHANGED) { 139 | ar = (AsyncResult) msg.obj; 140 | if (ar != null && ar.result != null) { 141 | iccStatusChanged((Integer) ar.result); 142 | } 143 | } 144 | } 145 | }; 146 | 147 | mPhones = phones; 148 | 149 | mSubscriptionManager = (SubscriptionManager) mContext.getSystemService( 150 | Context.TELEPHONY_SUBSCRIPTION_SERVICE); 151 | 152 | mTelecomManager = TelecomManager.from(context); 153 | 154 | mTelephonyManager = TelephonyManager.from(context); 155 | 156 | // Assume everything present is provisioned by default 157 | mUiccStatus = new UiccStatus[mPhones.length]; 158 | for (int i = 0; i < mPhones.length; i++) { 159 | if (mPhones[i] == null) { 160 | mUiccStatus[i] = null; 161 | } else if (mPhones[i].getUiccCard() == null) { 162 | mUiccStatus[i] = new UiccStatus(CARD_NOT_PRESENT); 163 | } else { 164 | mUiccStatus[i] = new UiccStatus(mPhones[i].getUiccCard().getCardState() 165 | == CARDSTATE_PRESENT ? PROVISIONED : CARD_NOT_PRESENT); 166 | } 167 | } 168 | 169 | mBusy = false; 170 | 171 | mUiccController = UiccController.getInstance(); 172 | mUiccController.registerForIccChanged(mHandler, EVENT_ICC_CHANGED, null); 173 | } 174 | 175 | private synchronized void iccStatusChanged(int slotId) { 176 | if (slotId >= mPhones.length || mPhones[slotId] == null) { 177 | return; 178 | } 179 | 180 | UiccCard card = mPhones[slotId].getUiccCard(); 181 | 182 | if (card == null || card.getCardState() != CARDSTATE_PRESENT) { 183 | mUiccStatus[slotId].mStatus = CARD_NOT_PRESENT; 184 | } else { 185 | if (mUiccStatus[slotId].mProvisioned && 186 | mUiccStatus[slotId].mStatus != PROVISIONED) { 187 | mUiccStatus[slotId].mStatus = NOT_PROVISIONED; 188 | activateUiccCard(slotId); 189 | } else if (!mUiccStatus[slotId].mProvisioned && 190 | mUiccStatus[slotId].mStatus != NOT_PROVISIONED) { 191 | mUiccStatus[slotId].mStatus = PROVISIONED; 192 | deactivateUiccCard(slotId); 193 | } 194 | } 195 | 196 | broadcastUiccActivation(slotId); 197 | } 198 | 199 | private void setUiccActivation(int slotId, boolean activate) { 200 | UiccCard card = mPhones[slotId].getUiccCard(); 201 | 202 | int numApps = card.getNumApplications(); 203 | 204 | mUiccStatus[slotId].mProvisioned = activate; 205 | 206 | for (int i = 0; i < numApps; i++) { 207 | if (card.getApplicationIndex(i) == null) { 208 | continue; 209 | } 210 | 211 | mCommandsInterfaces[slotId].setUiccSubscription(i, activate, null); 212 | } 213 | } 214 | 215 | private void broadcastUiccActivation(int slotId) { 216 | Intent intent = new Intent(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED); 217 | intent.putExtra(PhoneConstants.PHONE_KEY, slotId); 218 | intent.putExtra(EXTRA_NEW_PROVISION_STATE, mUiccStatus[slotId].mStatus); 219 | mContext.sendBroadcast(intent); 220 | } 221 | 222 | @Override 223 | public int getCurrentUiccCardProvisioningStatus(int slotId) { 224 | if (slotId >= mUiccStatus.length || mUiccStatus[slotId] == null) { 225 | return INVALID_INPUT; 226 | } 227 | 228 | return mUiccStatus[slotId].mStatus; 229 | } 230 | 231 | @Override 232 | public int getUiccCardProvisioningUserPreference(int slotId) { 233 | if (slotId >= mUiccStatus.length || mUiccStatus[slotId] == null) { 234 | return INVALID_INPUT; 235 | } 236 | 237 | return mUiccStatus[slotId].mProvisioned ? PROVISIONED : NOT_PROVISIONED; 238 | } 239 | 240 | @Override 241 | public int activateUiccCard(int slotId) { 242 | if (slotId >= mPhones.length || mPhones[slotId] == null || 243 | slotId >= mCommandsInterfaces.length || mCommandsInterfaces[slotId] == null) { 244 | return INVALID_INPUT; 245 | } 246 | 247 | if (mBusy) { 248 | return BUSY; 249 | } 250 | 251 | if (mUiccStatus[slotId].mStatus == PROVISIONED) { 252 | return SUCCESS; 253 | } 254 | 255 | if (mUiccStatus[slotId].mStatus != NOT_PROVISIONED) { 256 | return INVALID_INPUT; 257 | } 258 | 259 | mBusy = true; 260 | 261 | mUiccStatus[slotId].mStatus = PROVISIONED; 262 | 263 | setUiccActivation(slotId, true); 264 | mPhones[slotId].setVoiceActivationState(SIM_ACTIVATION_STATE_ACTIVATED); 265 | mPhones[slotId].setDataActivationState(SIM_ACTIVATION_STATE_ACTIVATED); 266 | 267 | mBusy = false; 268 | 269 | broadcastUiccActivation(slotId); 270 | 271 | return SUCCESS; 272 | } 273 | 274 | @Override 275 | public int deactivateUiccCard(int slotId) { 276 | if (slotId >= mPhones.length || mPhones[slotId] == null || 277 | slotId >= mCommandsInterfaces.length || mCommandsInterfaces[slotId] == null) { 278 | return INVALID_INPUT; 279 | } 280 | 281 | if (mBusy) { 282 | return BUSY; 283 | } 284 | 285 | if (mUiccStatus[slotId].mStatus == NOT_PROVISIONED) { 286 | return SUCCESS; 287 | } 288 | 289 | if (mUiccStatus[slotId].mStatus != PROVISIONED) { 290 | return INVALID_INPUT; 291 | } 292 | 293 | mBusy = true; 294 | 295 | int subIdToDeactivate = mPhones[slotId].getSubId(); 296 | int subIdToMakeDefault = INVALID_SUBSCRIPTION_ID; 297 | 298 | mUiccStatus[slotId].mStatus = NOT_PROVISIONED; 299 | 300 | // Find first provisioned sub that isn't what we're deactivating 301 | for (int i = 0; i < mPhones.length; i++) { 302 | if (mUiccStatus[i].mStatus == PROVISIONED) { 303 | subIdToMakeDefault = mPhones[i].getSubId(); 304 | break; 305 | } 306 | } 307 | 308 | // Make sure defaults are now sane 309 | PhoneAccountHandle accountHandle = mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 310 | PhoneAccount account = mTelecomManager.getPhoneAccount(accountHandle); 311 | 312 | if (mSubscriptionManager.getDefaultSmsSubscriptionId() == subIdToDeactivate) { 313 | mSubscriptionManager.setDefaultSmsSubId(subIdToMakeDefault); 314 | } 315 | 316 | if (mSubscriptionManager.getDefaultDataSubscriptionId() == subIdToDeactivate) { 317 | mSubscriptionManager.setDefaultDataSubId(subIdToMakeDefault); 318 | } 319 | 320 | if (mTelephonyManager.getSubIdForPhoneAccount(account) == subIdToDeactivate) { 321 | mTelecomManager.setUserSelectedOutgoingPhoneAccount( 322 | subscriptionIdToPhoneAccountHandle(subIdToMakeDefault)); 323 | } 324 | 325 | mPhones[slotId].setVoiceActivationState(SIM_ACTIVATION_STATE_DEACTIVATED); 326 | mPhones[slotId].setDataActivationState(SIM_ACTIVATION_STATE_DEACTIVATED); 327 | setUiccActivation(slotId, false); 328 | 329 | mBusy = false; 330 | 331 | broadcastUiccActivation(slotId); 332 | 333 | return SUCCESS; 334 | } 335 | 336 | @Override 337 | public boolean isSMSPromptEnabled() { 338 | // I hope we don't use this 339 | return false; 340 | } 341 | 342 | @Override 343 | public void setSMSPromptEnabled(boolean enabled) { 344 | // I hope we don't use this 345 | } 346 | 347 | @Override 348 | public int getPhoneIdForECall() { 349 | // I hope we don't use this 350 | return -1; 351 | } 352 | 353 | @Override 354 | public void setPrimaryCardOnSlot(int slotId) { 355 | // I hope we don't use this 356 | } 357 | 358 | @Override 359 | public boolean isFdnEnabled() { 360 | // I hope we don't use this 361 | return false; 362 | } 363 | 364 | @Override 365 | public int getPrimaryStackPhoneId() { 366 | // I hope we don't use this 367 | return -1; 368 | } 369 | 370 | @Override 371 | public boolean isEmergencyNumber(String number) { 372 | // This is lame... 373 | return PhoneNumberUtils.isEmergencyNumber(number); 374 | } 375 | 376 | @Override 377 | public boolean isLocalEmergencyNumber(String number) { 378 | // This is lame... 379 | return PhoneNumberUtils.isLocalEmergencyNumber(mContext, number); 380 | } 381 | 382 | @Override 383 | public boolean isPotentialEmergencyNumber(String number) { 384 | // This is lame... 385 | return PhoneNumberUtils.isPotentialEmergencyNumber(number); 386 | } 387 | 388 | @Override 389 | public boolean isPotentialLocalEmergencyNumber(String number) { 390 | // This is lame... 391 | return PhoneNumberUtils.isPotentialLocalEmergencyNumber(mContext, number); 392 | } 393 | 394 | @Override 395 | public boolean isDeviceInSingleStandby() { 396 | // I hope we don't use this 397 | return false; 398 | } 399 | 400 | @Override 401 | public boolean setLocalCallHold(int subId, boolean enable) { 402 | // TODO: Do something here 403 | return false; 404 | } 405 | 406 | @Override 407 | public void switchToActiveSub(int subId) { 408 | // I hope we don't use this 409 | } 410 | 411 | @Override 412 | public void setDsdaAdapter(IDsda dsdaAdapter) { 413 | // I hope we don't use this 414 | } 415 | 416 | @Override 417 | public int getActiveSubscription() { 418 | // I hope we don't use this 419 | return -1; 420 | } 421 | 422 | @Override 423 | public boolean isDsdaEnabled() { 424 | return mTelephonyManager.getMultiSimConfiguration() == DSDA; 425 | } 426 | 427 | @Override 428 | public void supplyIccDepersonalization(String netpin, String type, IDepersoResCallback callback, 429 | int phoneId) { 430 | // I hope we don't use this 431 | } 432 | 433 | @Override 434 | public int getPrimaryCarrierSlotId() { 435 | // I hope we don't use this 436 | return -1; 437 | } 438 | 439 | @Override 440 | public boolean isPrimaryCarrierSlotId(int slotId) { 441 | // I hope we don't use this 442 | return false; 443 | } 444 | 445 | @Override 446 | public boolean setSmscAddress(int slotId, String smsc) { 447 | // I hope we don't use this 448 | return false; 449 | } 450 | 451 | @Override 452 | public String getSmscAddress(int slotId) { 453 | // I hope we don't use this 454 | return null; 455 | } 456 | 457 | @Override 458 | public boolean isVendorApkAvailable(String packageName) { 459 | // I hope we don't use this 460 | return false; 461 | } 462 | 463 | @Override 464 | public int getCurrentPrimaryCardSlotId() { 465 | // I hope we don't use this 466 | return -1; 467 | } 468 | 469 | @Override 470 | public Token enable5g(int slotId, Client client) { 471 | // I hope we don't use this 472 | return new Token(-1); 473 | } 474 | 475 | @Override 476 | public Token disable5g(int slotId, Client client) { 477 | // I hope we don't use this 478 | return new Token(-1); 479 | } 480 | 481 | @Override 482 | public Token enable5gOnly(int slotId, Client client) { 483 | // I hope we don't use this 484 | return new Token(-1); 485 | } 486 | 487 | @Override 488 | public Token query5gStatus(int slotId, Client client) { 489 | // I hope we don't use this 490 | return new Token(-1); 491 | } 492 | 493 | @Override 494 | public Token queryNrDcParam(int slotId, Client client) { 495 | // I hope we don't use this 496 | return new Token(-1); 497 | } 498 | 499 | @Override 500 | public Token queryNrBearerAllocation(int slotId, Client client) { 501 | // I hope we don't use this 502 | return new Token(-1); 503 | } 504 | 505 | @Override 506 | public Token queryNrSignalStrength(int slotId, Client client) { 507 | // I hope we don't use this 508 | return new Token(-1); 509 | } 510 | 511 | @Override 512 | public Client registerCallback(String packageName, INetworkCallback callback) { 513 | // I hope we don't use this 514 | return new Client(-1, -1, packageName, callback); 515 | } 516 | 517 | @Override 518 | public void unRegisterCallback(INetworkCallback callback) { 519 | // I hope we don't use this 520 | } 521 | 522 | private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) { 523 | final Iterator phoneAccounts = 524 | mTelecomManager.getCallCapablePhoneAccounts().listIterator(); 525 | 526 | while (phoneAccounts.hasNext()) { 527 | final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next(); 528 | final PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(phoneAccountHandle); 529 | if (subId == mTelephonyManager.getSubIdForPhoneAccount(phoneAccount)) { 530 | return phoneAccountHandle; 531 | } 532 | } 533 | 534 | return null; 535 | } 536 | 537 | } 538 | --------------------------------------------------------------------------------