ממשקי API של eUICC

ב-Android 9, ממשקי ה-API לניהול פרופילים (ציבוריים ו-@SystemApi) זמינים דרך הכיתה EuiccManager. ממשקי ה-API של תקשורת eUICC זמינים דרך הכיתה EuiccCardManager (רק @SystemApi).

מידע על eUICC

ספקי הסלולר יכולים ליצור אפליקציות ספקי סלולר באמצעות EuiccManager כדי לנהל את הפרופילים, כפי שמוצג באיור 1. אפליקציות של ספקי סלולר לא חייבות להיות אפליקציות מערכת, אבל הן צריכות לקבל הרשאות של ספק הסלולר באמצעות פרופילים של eUICC. אפליקציית LPA (LUI ו-LPA לקצה העורפי) צריכה להיות אפליקציית מערכת (כלומר, כלולה בתמונת המערכת) כדי לקרוא ל-@SystemApi.

טלפון Android עם אפליקציית ספק ו-OEM LPA

איור 1. טלפונים עם Android עם אפליקציית ספק ו-LPA של יצרן ציוד מקורי

מלבד הלוגיקה של קריאה ל-EuiccCardManager ושל שיחה עם eUICC, אפליקציות LPA חייבות להטמיע את הדברים הבאים:

  • לקוח SM-DP+‎ שמדבר עם שרת SM-DP+‎ כדי לאמת ולהוריד פרופילים
  • [אופציונלי] SM-DS כדי לקבל פרופילים פוטנציאליים נוספים שניתנים להורדה
  • טיפול בהתראות לשליחת התראות לשרת כדי לעדכן את מצב הפרופיל
  • [אופציונלי] ניהול משבצות, כולל מעבר בין הלוגיקה של eSIM לבין הלוגיקה של pSIM. האפשרות הזו אופציונלית אם בטלפון יש רק צ'יפ eSIM.
  • eSIM OTA

אפשר להתקין בטלפון Android יותר מאפליקציית LPA אחת, אבל רק אפליקציית LPA אחת יכולה להיות פעילה, על סמך העדיפות שמוגדרת בקובץ AndroidManifest.xml של כל אפליקציה.

שימוש ב-EuiccManager

ממשקי ה-API של LPA גלויים לכולם דרך EuiccManager (בתוך החבילה android.telephony.euicc). אפליקציה של ספק יכולה לקבל את המכונה של EuiccManager ולקרוא לשיטות ב-EuiccManager כדי לקבל את המידע של eUICC ולנהל את המינויים (שנקראים פרופילים במסמכי GSMA RSP) בתור מכונות SubscriptionInfo.

כדי להפעיל ממשקי API ציבוריים, כולל פעולות הורדה, החלפה ומחיקה של מינויים, לאפליקציית הספק צריכות להיות ההרשאות הנדרשות. ספק הסלולר מוסיף את ההרשאות שלו למטא-נתונים של הפרופיל. ממשק eUICC API אוכף את כללי הרשאות הספק בהתאם.

פלטפורמת Android לא מטפלת בכללי מדיניות הפרופיל. אם כלל מדיניות מוצהר במטא-נתונים של הפרופיל, ה-LPA יכול לבחור איך לטפל בתהליך ההורדה וההתקנה של הפרופיל. לדוגמה, אפשר לאפשר ל-LPA של OEM של צד שלישי לטפל בכללי מדיניות באמצעות קוד שגיאה מיוחד (קוד השגיאה מועבר מה-LPA של OEM לפלטפורמה, ואז הפלטפורמה מעבירה את הקוד ל-LUI של OEM).

מידע על ממשקי API של כמה פרופילים מופעלים זמין במאמר כמה פרופילים מופעלים.

ממשקי API

ממשקי ה-API הבאים מופיעים במאמרי העזרה של EuiccManager וב-EuiccManager.java.

אחזור מכונה (ציבורי)

הפונקציה מקבלת את המופע של EuiccManager דרך Context#getSystemService. פרטים נוספים זמינים במאמר getSystemService.

EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);

בודקים אם האפשרות מופעלת (גלויה לכולם)

בדיקה אם המינוי המוטמע מופעל. צריך לבדוק את זה לפני שניגשים לממשקי API של LPA. פרטים נוספים זמינים במאמר isEnabled.

boolean isEnabled = mgr.isEnabled();
if (!isEnabled) {
    return;
}

אחזור EID (גלוי לכולם)

הפונקציה מקבלת את ה-EID שמזהה את חומרת ה-eUICC. הערך הזה יכול להיות null אם ה-eUICC לא מוכן. למבצע הקריאה החוזרת צריכה להיות הרשאת ספק או ההרשאה READ_PRIVILEGED_PHONE_STATE. למידע נוסף: getEid.

String eid = mgr.getEid();
if (eid == null) {
  // Handle null case.
}

אחזור EuiccInfo (גלוי לכולם)

קבלת מידע על eUICC. כאן מופיעה גרסת מערכת ההפעלה. פרטים נוספים זמינים במאמר getEuiccInfo.

EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();

הורדת מינוי (ציבורי)

הורדת המינוי הנתון (שנקרא 'פרופיל' במסמכי GSMA RSP). אפשר ליצור את המינוי באמצעות קוד הפעלה. לדוגמה, אפשר לנתח קוד הפעלה מקוד QR. הורדת המינוי היא פעולה אסינכרונית.

למבצע הקריאה החוזרת צריכה להיות ההרשאה WRITE_EMBEDDED_SUBSCRIPTIONS או הרשאות ספק במינוי היעד. פרטים נוספים זמינים במאמר downloadSubscription.

// Register receiver.
String action = "download_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(
        receiver,
        new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Download subscription asynchronously.
DownloadableSubscription sub =
        DownloadableSubscription.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.downloadSubscription(sub, true /* switchAfterDownload */, callbackIntent);

החלפת מינוי (ציבורי)

מעבר למינוי הנתון (הפעלה שלו). למבצע הקריאה החוזרת צריכה להיות WRITE_EMBEDDED_SUBSCRIPTIONS או שיהיו לו הרשאות ספק במינוי הנוכחי שמופעל בו ובמינוי היעד. פרטים נוספים זמינים במאמר switchToSubscription.

// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);

החלפת מינוי עם יציאה (גלוי לכולם)

(זמין מ-Android 13) מעבר למינוי הנתון עם מדד היציאה שצוין (הפעלה). למבצע הקריאה החוזרת צריכה להיות ההרשאה WRITE_EMBEDDED_SUBSCRIPTIONS או הרשאות ספק לטלפון נייד עבור המינוי המופעל הנוכחי והמינוי היעד. פרטים נוספים זמינים במאמר switchToSubscription.

// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/, null /* handler */);

// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, 0 /*portIndex*/, callbackIntent);

האם יציאת כרטיס ה-SIM זמינה (ציבורית)

public boolean isSimPortAvailable(int portIndex)

(זמין מ-Android 13) הפונקציה מחזירה אם אינדקס השקע המעביר זמין. אפשר יציאה אם אין מינוי מופעל, או אם לאפליקציית השיחות יש הרשאת ספק על פני המינוי שמותקן ביציאה שנבחרה. פרטים נוספים זמינים במאמר isSimPortAvailable.

מחיקת מינוי (גלוי לכולם)

מחיקה של מינוי לפי מזהה מינוי. אם המינוי פעיל כרגע, הוא יושבת קודם. למבצע הקריאה החוזרת צריכות להיות WRITE_EMBEDDED_SUBSCRIPTIONS או הרשאות ספק במינוי היעד. פרטים נוספים זמינים במאמר deleteSubscription.

// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Delete a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.deleteSubscription(1 /* subscriptionId */, callbackIntent);

מחיקה של כל המינויים (System API)

מחיקה של כל המינויים במכשיר. החל מגרסה Android 11, צריך לספק ערך enum של EuiccCardManager#ResetOption כדי לציין אם למחוק את כל המינויים לבדיקה, את כל המינויים התפעוליים או את שני סוגי המינויים. למבצע הקריאה החוזרת צריכה להיות הרשאה WRITE_EMBEDDED_SUBSCRIPTIONS.

// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);
                resultIntent = intent;
            }
        };
context.registerReceiver(receiver, new IntentFilter(action),
        "example.broadcast.permission" /* broadcastPermission*/,
        null /* handler */);

// Erase all operational subscriptions asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.eraseSubscriptions(
        EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, callbackIntent);

התחלת פעילות פתרון (גלויה לכולם)

הפעלת פעילות לפתרון שגיאה שהמשתמש יכול לפתור. אם פעולה מחזירה את הערך EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, אפשר לקרוא לשיטה הזו כדי לבקש מהמשתמש לפתור את הבעיה. אפשר לקרוא לשיטה הזו רק פעם אחת לכל שגיאה מסוימת.

...
mgr.startResolutionActivity(getActivity(), 0 /* requestCode */, resultIntent, callbackIntent);

קבועים

רשימה של הקבועים public ב-EuiccManager מופיעה במאמר קבועים.