[Settings] Present EID in About phone page
Present EID within about phone page.
Bug: 260540995
Test: local
Change-Id: If5f512c1da6b4b3b1adc1d13dbe11226b7ecad41
diff --git a/res/layout/dialog_eid_status.xml b/res/layout/dialog_eid_status.xml
new file mode 100644
index 0000000..95d4872
--- /dev/null
+++ b/res/layout/dialog_eid_status.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="@dimen/sim_content_padding">
+
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/esim_id_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textIsSelectable="true"
+ android:text="@string/device_info_not_available"/>
+
+ <ImageView
+ android:id="@+id/esim_id_qrcode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:ignore="ContentDescription" />
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a97c3d5..2a2cccf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2415,6 +2415,10 @@
<string name="storage_settings_for_app" >Storage & cache</string>
<!-- Storage settings screen title -->
<string name="storage_settings_title">Storage settings</string>
+ <!-- About phone, title of EID -->
+ <string name="status_eid">EID</string>
+ <!-- About phone, title of EID for multi-sim devices -->
+ <string name="eid_multi_sim">EID (sim slot %1$d)</string>
<!-- About phone screen, title for IMEI for multi-sim devices -->
<string name="imei_multi_sim">IMEI (sim slot %1$d)</string>
<!-- About phone screen, summary of the MAC address [CHAR LIMIT=80] -->
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 9f14026..4cbe13f 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -105,7 +105,7 @@
<!-- Model & hardware -->
<Preference
android:key="device_model"
- android:order="31"
+ android:order="30"
android:title="@string/model_info"
android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFragment"
@@ -113,6 +113,18 @@
settings:keywords="@string/keywords_model_and_hardware"
settings:controller="com.android.settings.deviceinfo.HardwareInfoPreferenceController"/>
+ <!-- EID -->
+ <com.android.settings.network.telephony.TelephonyPreferenceDialog
+ android:key="eid_info"
+ android:order="31"
+ android:title="@string/status_eid"
+ android:summary="@string/device_info_protected_single_press"
+ android:positiveButtonText="@string/dlg_ok"
+ android:dialogLayout="@layout/dialog_eid_status"
+ settings:isPreferenceVisible="@bool/config_show_sim_info"
+ settings:enableCopying="true"
+ settings:controller="com.android.settings.deviceinfo.simstatus.SimEidPreferenceController"/>
+
<!-- IMEI -->
<com.android.settings.deviceinfo.PhoneNumberSummaryPreference
android:key="imei_info"
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 22b38d6..991ad25 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -40,6 +40,8 @@
import com.android.settings.deviceinfo.UptimePreferenceController;
import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController;
+import com.android.settings.deviceinfo.simstatus.EidStatus;
+import com.android.settings.deviceinfo.simstatus.SimEidPreferenceController;
import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceController;
import com.android.settings.deviceinfo.simstatus.SlotSimStatus;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -59,6 +61,7 @@
implements DeviceNamePreferenceController.DeviceNamePreferenceHost {
private static final String LOG_TAG = "MyDeviceInfoFragment";
+ private static final String KEY_EID_INFO = "eid_info";
private static final String KEY_MY_DEVICE_INFO_HEADER = "my_device_info_header";
private BuildNumberPreferenceController mBuildNumberPreferenceController;
@@ -130,6 +133,12 @@
slotRecord.init(fragment, slotSimStatus);
controllers.add(slotRecord);
}
+
+ EidStatus eidStatus = new EidStatus(slotSimStatus, context, executor);
+ SimEidPreferenceController simEid = new SimEidPreferenceController(context, KEY_EID_INFO);
+ simEid.init(slotSimStatus, eidStatus);
+ controllers.add(simEid);
+
if (executor != null) {
executor.shutdown();
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/EidStatus.java b/src/com/android/settings/deviceinfo/simstatus/EidStatus.java
new file mode 100644
index 0000000..2f986a3
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/simstatus/EidStatus.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 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.settings.deviceinfo.simstatus;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
+import android.telephony.euicc.EuiccManager;
+import android.text.TextUtils;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.IntStream;
+
+/**
+ * A class for query EID.
+ */
+public class EidStatus {
+
+ private static final String TAG = "EidStatus";
+ private final SlotSimStatus mSlotSimStatus;
+ private final Phaser mBlocker = new Phaser(1);
+ private final AtomicReference<String> mEid = new AtomicReference<String>();
+
+ /**
+ * Construct of class.
+ * @param slotSimStatus SlotSimStatus
+ * @param context Context
+ */
+ public EidStatus(SlotSimStatus slotSimStatus, Context context) {
+ this(slotSimStatus, context, null);
+ }
+
+ /**
+ * Construct of class.
+ * @param slotSimStatus SlotSimStatus
+ * @param context Context
+ * @param executor executor for offload to thread
+ */
+ public EidStatus(SlotSimStatus slotSimStatus, Context context, Executor executor) {
+ mSlotSimStatus = slotSimStatus;
+
+ if (executor == null) {
+ getEidOperation(context);
+ } else {
+ executor.execute(() -> getEidOperation(context));
+ }
+ }
+
+ /**
+ * Get the EID
+ * @return EID string
+ */
+ public String getEid() {
+ mBlocker.awaitAdvance(0);
+ return mEid.get();
+ }
+
+ protected TelephonyManager getTelephonyManager(Context context) {
+ return context.getSystemService(TelephonyManager.class);
+ }
+
+ protected EuiccManager getEuiccManager(Context context) {
+ return context.getSystemService(EuiccManager.class);
+ }
+
+ protected String getDefaultEid(EuiccManager euiccMgr) {
+ if ((euiccMgr == null) || (!euiccMgr.isEnabled())) {
+ return null;
+ }
+ return euiccMgr.getEid();
+ }
+
+ protected void getEidOperation(Context context) {
+ EuiccManager euiccMgr = getEuiccManager(context);
+ String eid = getEidPerSlot(context, euiccMgr);
+ if (eid == null) {
+ eid = getDefaultEid(euiccMgr);
+ }
+ mEid.set(eid);
+ mBlocker.arrive();
+ }
+
+ protected String getEidPerSlot(Context context, EuiccManager euiccMgr) {
+ if (mSlotSimStatus.size() <= SimStatusDialogController.MAX_PHONE_COUNT_SINGLE_SIM) {
+ return null;
+ }
+
+ TelephonyManager telMgr = getTelephonyManager(context);
+ if (telMgr == null) {
+ return null;
+ }
+
+ List<UiccCardInfo> uiccCardInfoList = telMgr.getUiccCardsInfo();
+ if (uiccCardInfoList == null) {
+ return null;
+ }
+
+ // Collects all card ID from all eSIM(s) reported from SubscsriptionManager
+ final int [] cardIdList = IntStream.range(0, mSlotSimStatus.size())
+ .mapToObj(slotIdx -> mSlotSimStatus.getSubscriptionInfo(slotIdx))
+ .filter(Objects::nonNull)
+ .filter(SubscriptionInfo::isEmbedded)
+ .mapToInt(SubscriptionInfo::getCardId)
+ .sorted()
+ .distinct()
+ .toArray();
+ if (cardIdList.length == 0) {
+ return null;
+ }
+
+ /**
+ * Find EID from first slot which contains an eSIM and with card ID listed within
+ * the eSIM card ID provided by SubscsriptionManager.
+ */
+ return uiccCardInfoList.stream()
+ .filter(UiccCardInfo::isEuicc)
+ .filter(cardInfo -> {
+ int cardId = cardInfo.getCardId();
+ return Arrays.binarySearch(cardIdList, cardId) >= 0;
+ })
+ .map(cardInfo -> {
+ String eid = cardInfo.getEid();
+ if (TextUtils.isEmpty(eid)) {
+ eid = euiccMgr.createForCardId(cardInfo.getCardId()).getEid();
+ }
+ return eid;
+ })
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.java
new file mode 100644
index 0000000..e0a8af6
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 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.settings.deviceinfo.simstatus;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.deviceinfo.PhoneNumberUtil;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.telephony.TelephonyPreferenceDialog;
+import com.android.settingslib.Utils;
+import com.android.settingslib.qrcode.QrCodeGenerator;
+
+/**
+ * This is to show a preference regarding EID of SIM card.
+ */
+public class SimEidPreferenceController extends BasePreferenceController
+ implements DialogInterface.OnShowListener {
+
+ private static final String TAG = "SimEidPreferenceController";
+
+ private SlotSimStatus mSlotSimStatus;
+ private EidStatus mEidStatus;
+ private boolean mShowEidOnSummary;
+ private TelephonyPreferenceDialog mPreference;
+
+ /**
+ * Constructer.
+ * @param context Context
+ * @param preferenceKey is the key for Preference
+ */
+ public SimEidPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ /**
+ * Update status.
+ *
+ * @param slotSimStatus sim status per slot
+ * @param eidStatus status of EID
+ */
+ public void init(SlotSimStatus slotSimStatus, EidStatus eidStatus) {
+ mSlotSimStatus = slotSimStatus;
+ mEidStatus = eidStatus;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if ((!SubscriptionUtil.isSimHardwareVisible(mContext)) || (mSlotSimStatus == null)) {
+ return;
+ }
+ TelephonyPreferenceDialog preference = (TelephonyPreferenceDialog)
+ screen.findPreference(getPreferenceKey());
+ if (preference == null) {
+ return;
+ }
+
+ preference.setTitle(getTitle());
+ mPreference = preference;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ TelephonyPreferenceDialog preferenceDialog = (TelephonyPreferenceDialog)preference;
+ preferenceDialog.setDialogTitle(getTitle());
+ preferenceDialog.setDialogMessage(mEidStatus.getEid());
+ preferenceDialog.setOnShowListener(this);
+ return true;
+ }
+ return super.handlePreferenceTreeClick(preference);
+ }
+
+ /**
+ * Construct title string.
+ * @return title string
+ */
+ @VisibleForTesting
+ protected CharSequence getTitle() {
+ int slotSize = (mSlotSimStatus == null) ? 0 : mSlotSimStatus.size();
+ if (slotSize <= SimStatusDialogController.MAX_PHONE_COUNT_SINGLE_SIM) {
+ return mContext.getString(R.string.status_eid);
+ }
+ // Only append slot index to title when more than 1 is available
+ for (int idxSlot = 0; idxSlot < slotSize; idxSlot++) {
+ SubscriptionInfo subInfo = mSlotSimStatus.getSubscriptionInfo(idxSlot);
+ if ((subInfo != null) && subInfo.isEmbedded()) {
+ return mContext.getString(R.string.eid_multi_sim, idxSlot+1);
+ }
+ }
+ return mContext.getString(R.string.status_eid);
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ String summary = mShowEidOnSummary ? mEidStatus.getEid() : null;
+ if (TextUtils.isEmpty(summary)) {
+ summary = mContext.getString(R.string.device_info_protected_single_press);
+ }
+ return summary;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (!SubscriptionUtil.isSimHardwareVisible(mContext)) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ boolean isAvailable = SubscriptionUtil.isSimHardwareVisible(mContext) &&
+ mContext.getSystemService(UserManager.class).isAdminUser() &&
+ !Utils.isWifiOnly(mContext);
+ return isAvailable ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ /**
+ * Callback when dialog end of show().
+ */
+ public void onShow(DialogInterface dialog) {
+ Dialog dialogShwon = mPreference.getDialog();
+
+ dialogShwon.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE);
+ dialogShwon.setCanceledOnTouchOutside(false);
+
+ TextView textView = dialogShwon.findViewById(R.id.esim_id_value);
+ textView.setText(PhoneNumberUtil.expandByTts(mEidStatus.getEid()));
+ textView.setTextIsSelectable(true);
+
+ ImageView qrCodeView = dialogShwon.findViewById(R.id.esim_id_qrcode);
+ qrCodeView.setImageBitmap(getEidQRcode(mEidStatus.getEid().toString(),
+ qrCodeView.getWidth()));
+
+ mShowEidOnSummary = true;
+ }
+
+ /**
+ * Get the QR code for EID
+ * @param eid is the EID string
+ * @param widthInPixel is the width of Bitmap in pixel
+ * @return a Bitmap of QR code
+ */
+ public Bitmap getEidQRcode(String eid, int widthInPixel) {
+ Bitmap qrCodeBitmap = null;
+ try {
+ qrCodeBitmap = QrCodeGenerator.encodeQrCode(eid, widthInPixel);
+ } catch (Exception exception) {
+ Log.w(TAG, "Error when creating QR code width " + widthInPixel, exception);
+ }
+ return qrCodeBitmap;
+ }
+}