Merge "Revert "Update getRadioInterfaceCapabilities return type""
diff --git a/OWNERS b/OWNERS
index 3059d4d..e095b89 100644
--- a/OWNERS
+++ b/OWNERS
@@ -13,3 +13,4 @@
 dbright@google.com
 xiaotonj@google.com
 
+per-file *SimPhonebookProvider* = file:platform/packages/apps/Contacts:/OWNERS
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 5760527..9510cae 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -322,6 +322,7 @@
     private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE = 104;
     private static final int CMD_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST = 105;
     private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE = 106;
+    private static final int CMD_PREPARE_UNATTENDED_REBOOT = 109;
 
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
@@ -1524,7 +1525,7 @@
                     PhoneConfigurationManager.getInstance()
                             .enablePhone(request.phone, enable, onCompleted);
                     break;
-                case EVENT_ENABLE_MODEM_DONE:
+                case EVENT_ENABLE_MODEM_DONE: {
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
                     request.result = (ar.exception == null);
@@ -1539,6 +1540,7 @@
                     }
                     notifyRequester(request);
                     break;
+                }
                 case CMD_GET_MODEM_STATUS:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_GET_MODEM_STATUS_DONE, request);
@@ -1677,27 +1679,44 @@
                     request = (MainThreadRequest) ar.userObj;
                     if (ar.exception == null) {
                         request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+                        // If the operation is successful, update the PIN storage
+                        Pair<String, String> passwords = (Pair<String, String>) request.argument;
+                        int phoneId = getPhoneFromRequest(request).getPhoneId();
+                        UiccController.getInstance().getPinStorage()
+                                .storePin(passwords.second, phoneId);
                     } else {
                         request.result = msg.arg1;
                     }
                     notifyRequester(request);
                     break;
 
-                case CMD_SET_ICC_LOCK_ENABLED:
+                case CMD_SET_ICC_LOCK_ENABLED: {
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_SET_ICC_LOCK_ENABLED_DONE, request);
                     Pair<Boolean, String> enabled = (Pair<Boolean, String>) request.argument;
                     getPhoneFromRequest(request).getIccCard().setIccLockEnabled(
                             enabled.first, enabled.second, onCompleted);
                     break;
+                }
                 case EVENT_SET_ICC_LOCK_ENABLED_DONE:
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
                     if (ar.exception == null) {
                         request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+                        // If the operation is successful, update the PIN storage
+                        Pair<Boolean, String> enabled = (Pair<Boolean, String>) request.argument;
+                        int phoneId = getPhoneFromRequest(request).getPhoneId();
+                        if (enabled.first) {
+                            UiccController.getInstance().getPinStorage()
+                                    .storePin(enabled.second, phoneId);
+                        } else {
+                            UiccController.getInstance().getPinStorage().clearPin(phoneId);
+                        }
                     } else {
                         request.result = msg.arg1;
                     }
+
+
                     notifyRequester(request);
                     break;
 
@@ -1858,6 +1877,13 @@
                     break;
                 }
 
+                case CMD_PREPARE_UNATTENDED_REBOOT:
+                    request = (MainThreadRequest) msg.obj;
+                    request.result =
+                            UiccController.getInstance().getPinStorage().prepareUnattendedReboot();
+                    notifyRequester(request);
+                    break;
+
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
                     break;
@@ -2218,7 +2244,8 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
+            Phone phone = getPhone(subId);
+            final UnlockSim checkSimPin = new UnlockSim(phone.getPhoneId(), phone.getIccCard());
             checkSimPin.start();
             return checkSimPin.unlockSim(null, pin);
         } finally {
@@ -2231,7 +2258,8 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
+            Phone phone = getPhone(subId);
+            final UnlockSim checkSimPuk = new UnlockSim(phone.getPhoneId(), phone.getIccCard());
             checkSimPuk.start();
             return checkSimPuk.unlockSim(puk, pin);
         } finally {
@@ -2246,6 +2274,7 @@
     private static class UnlockSim extends Thread {
 
         private final IccCard mSimCard;
+        private final int mPhoneId;
 
         private boolean mDone = false;
         private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
@@ -2257,7 +2286,8 @@
         // For async handler to identify request type
         private static final int SUPPLY_PIN_COMPLETE = 100;
 
-        public UnlockSim(IccCard simCard) {
+        UnlockSim(int phoneId, IccCard simCard) {
+            mPhoneId = phoneId;
             mSimCard = simCard;
         }
 
@@ -2339,6 +2369,11 @@
             int[] resultArray = new int[2];
             resultArray[0] = mResult;
             resultArray[1] = mRetryCount;
+
+            if (mResult == PhoneConstants.PIN_RESULT_SUCCESS && pin.length() > 0) {
+                UiccController.getInstance().getPinStorage().storePin(pin, mPhoneId);
+            }
+
             return resultArray;
         }
     }
@@ -3137,6 +3172,10 @@
         mApp.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS, null);
     }
 
+    private void enforceRebootPermission() {
+        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+    }
+
     private String createTelUrl(String number) {
         if (TextUtils.isEmpty(number)) {
             return null;
@@ -10009,4 +10048,21 @@
             }
         }
     }
+
+    /**
+     * Prepare TelephonyManager for an unattended reboot. The reboot is
+     * required to be done shortly after the API is invoked.
+     */
+    @Override
+    @TelephonyManager.PrepareUnattendedRebootResult
+    public int prepareForUnattendedReboot() {
+        enforceRebootPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return (int) sendRequest(CMD_PREPARE_UNATTENDED_REBOOT, null);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
 }
diff --git a/src/com/android/phone/SimPhonebookProvider.java b/src/com/android/phone/SimPhonebookProvider.java
index 7a1e93c..6a27130 100644
--- a/src/com/android/phone/SimPhonebookProvider.java
+++ b/src/com/android/phone/SimPhonebookProvider.java
@@ -59,6 +59,7 @@
 import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
@@ -295,6 +296,9 @@
 
     private Cursor queryElementaryFilesItem(PhonebookArgs args, String[] projection) {
         validateProjection(ELEMENTARY_FILES_COLUMNS_SET, projection);
+        if (projection == null) {
+            projection = ELEMENTARY_FILES_ALL_COLUMNS;
+        }
 
         MatrixCursor result = new MatrixCursor(projection);
         try {
@@ -641,8 +645,8 @@
     }
 
     private boolean hasPermissionsForFdnWrite(PhonebookArgs args) {
-        TelephonyManager telephonyManager = getContext().getSystemService(
-                TelephonyManager.class);
+        TelephonyManager telephonyManager = Objects.requireNonNull(
+                getContext().getSystemService(TelephonyManager.class));
         String callingPackage = getCallingPackage();
         int granted = PackageManager.PERMISSION_DENIED;
         if (callingPackage != null) {
@@ -701,7 +705,12 @@
 
         String name = values.getAsString(SimRecords.NAME);
         int length = getEncodedNameLength(name);
-        int maxLength = AdnRecord.getMaxAlphaTagBytes(getRecordSize(getRecordsSizeForEf(args)));
+        int[] recordsSize = getRecordsSizeForEf(args);
+        if (recordsSize == null) {
+            throw new IllegalStateException(
+                    "Failed to get " + ElementaryFiles.NAME_MAX_LENGTH + " from SIM");
+        }
+        int maxLength = AdnRecord.getMaxAlphaTagBytes(getRecordSize(recordsSize));
 
         if (length > maxLength) {
             throw new IllegalArgumentException(SimRecords.NAME + " is too long.");
@@ -740,7 +749,7 @@
 
     private AdnRecord loadRecord(PhonebookArgs args) {
         List<AdnRecord> records = loadRecordsForEf(args);
-        if (args.recordNumber > records.size()) {
+        if (records == null || args.recordNumber > records.size()) {
             return null;
         }
         AdnRecord result = records.get(args.recordNumber - 1);
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index af293ce..8acfd1d 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -68,6 +68,7 @@
     private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
     private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
     private static final String RESTART_MODEM = "restart-modem";
+    private static final String UNATTENDED_REBOOT = "unattended-reboot";
     private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
     private static final String DATA_TEST_MODE = "data";
     private static final String DATA_ENABLE = "enable";
@@ -201,6 +202,8 @@
                 return handleSingleRegistrationConfigCommand();
             case RESTART_MODEM:
                 return handleRestartModemCommand();
+            case UNATTENDED_REBOOT:
+                return handleUnattendedReboot();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -231,6 +234,8 @@
         pw.println("    RCS VoLTE Single Registration Config Commands.");
         pw.println("  restart-modem");
         pw.println("    Restart modem command.");
+        pw.println("  unattended-reboot");
+        pw.println("    Prepare for unattended reboot.");
         onHelpIms();
         onHelpUce();
         onHelpEmergencyNumber();
@@ -1456,6 +1461,20 @@
         return result ? 0 : -1;
     }
 
+    private int handleUnattendedReboot() {
+        // Verify that the user is allowed to run the command. Only allowed in rooted device in a
+        // non user build.
+        if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
+            getErrPrintWriter().println("UnattendedReboot: Permission denied.");
+            return -1;
+        }
+
+        int result = TelephonyManager.getDefault().prepareForUnattendedReboot();
+        getOutPrintWriter().println("result: " + result);
+
+        return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1;
+    }
+
     private int handleGbaCommand() {
         String arg = getNextArg();
         if (arg == null) {
diff --git a/testapps/TestRcsApp/TestApp/Android.bp b/testapps/TestRcsApp/TestApp/Android.bp
index 49feff8..e63715b 100644
--- a/testapps/TestRcsApp/TestApp/Android.bp
+++ b/testapps/TestRcsApp/TestApp/Android.bp
@@ -18,6 +18,7 @@
         "androidx-constraintlayout_constraintlayout",
         "aosp_test_rcs_client_base",
         "androidx.appcompat_appcompat",
+        "libphonenumber-platform"
     ],
     certificate: "platform",
 
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index d57ec94..8f2d6bd 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -19,8 +19,8 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.google.android.sample.rcsclient"
-    android:versionCode="4"
-    android:versionName="1.0.3">
+    android:versionCode="5"
+    android:versionName="1.0.4">
 
     <uses-sdk
         android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/NumberUtils.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/NumberUtils.java
index 72cbf3f..14d3b9c 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/NumberUtils.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/util/NumberUtils.java
@@ -17,8 +17,12 @@
 package com.google.android.sample.rcsclient.util;
 
 import android.content.Context;
-import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.Phonenumber;
 
 public class NumberUtils {
 
@@ -30,6 +34,13 @@
     public static String formatNumber(Context context, String number) {
         TelephonyManager manager = context.getSystemService(TelephonyManager.class);
         String simCountryIso = manager.getSimCountryIso().toUpperCase();
-        return PhoneNumberUtils.formatNumberToE164(number, simCountryIso);
+        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+        try {
+            Phonenumber.PhoneNumber phoneNumber = util.parse(number, simCountryIso);
+            return util.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
+        } catch (NumberParseException e) {
+            Log.w("NumberUtils", "formatNumber: could not format " + number + ", error: " + e);
+        }
+        return null;
     }
 }
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/ImsPdnNetworkFetcher.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/ImsPdnNetworkFetcher.java
index 0011011..57bb75a 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/ImsPdnNetworkFetcher.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/ImsPdnNetworkFetcher.java
@@ -82,7 +82,7 @@
         return result;
     }
 
-    private ConnectivityManager getConnectivityManager() {
+    ConnectivityManager getConnectivityManager() {
         return context.getSystemService(ConnectivityManager.class);
     }
 }
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
index 47326bd..81abe89 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpManager.java
@@ -17,6 +17,7 @@
 package com.android.libraries.rcs.simpleclient.protocol.msrp;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.Network;
 
 import com.google.common.util.concurrent.Futures;
@@ -24,6 +25,7 @@
 import com.google.common.util.concurrent.MoreExecutors;
 
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.Socket;
 
 /** Provides creating and managing {@link MsrpSession} */
@@ -34,24 +36,27 @@
         imsPdnNetworkFetcher = new ImsPdnNetworkFetcher(context);
     }
 
-    private static MsrpSession createMsrpSession(
-            Network network, String host, int port, MsrpSessionListener listener)
-            throws IOException {
-        Socket socket = network.getSocketFactory().createSocket(host, port);
-        MsrpSession msrpSession = new MsrpSession(socket, listener);
+    private static MsrpSession createMsrpSession(ConnectivityManager manager,
+            Network network, String host, int port, String localIp, int localPort,
+            MsrpSessionListener listener) throws IOException {
+        Socket socket = network.getSocketFactory().createSocket(host, port,
+                InetAddress.getByName(localIp), localPort);
+        MsrpSession msrpSession = new MsrpSession(manager,
+                network, socket, listener);
         Thread thread = new Thread(msrpSession::run);
         thread.start();
         return msrpSession;
     }
 
     public ListenableFuture<MsrpSession> createMsrpSession(
-            String host, int port, MsrpSessionListener listener) {
+            String host, int port, String localIp, int localPort, MsrpSessionListener listener) {
         return Futures.transformAsync(
                 imsPdnNetworkFetcher.getImsPdnNetwork(),
                 network -> {
                     if (network != null) {
                         return Futures.immediateFuture(
-                                createMsrpSession(network, host, port, listener));
+                                createMsrpSession(imsPdnNetworkFetcher.getConnectivityManager(),
+                                        network, host, port, localIp, localPort, listener));
                     } else {
                         return Futures.immediateFailedFuture(
                                 new IllegalStateException("Network is null"));
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
index 96ca19c..3f8b986 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java
@@ -19,6 +19,16 @@
 import static com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Method.SEND;
 import static com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Method.UNKNOWN;
 
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.QosCallback;
+import android.net.QosCallbackException;
+import android.net.QosSession;
+import android.net.QosSessionAttributes;
+import android.net.QosSocketInfo;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 
@@ -26,6 +36,7 @@
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -38,6 +49,7 @@
  * Provides MSRP sending and receiving messages ability.
  */
 public class MsrpSession {
+    private final Network network;
     private final Socket socket;
     private final InputStream input;
     private final OutputStream output;
@@ -45,13 +57,51 @@
     private final ConcurrentHashMap<String, MsrpTransaction> transactions =
             new ConcurrentHashMap<>();
     private final MsrpSessionListener listener;
+    private final ConnectivityManager connectivityManager;
+    private final String LOG_TAG = MsrpSession.class.getSimpleName();
 
     /** Creates a new MSRP session on the given listener and the provided streams. */
-    MsrpSession(Socket socket, MsrpSessionListener listener) throws IOException {
+    MsrpSession(ConnectivityManager connectivityManager, Network network, Socket socket,
+            MsrpSessionListener listener) throws IOException {
+        this.connectivityManager = connectivityManager;
+        this.network = network;
         this.socket = socket;
         this.input = socket.getInputStream();
         this.output = socket.getOutputStream();
         this.listener = listener;
+
+        listenForBearer();
+    }
+
+    private final QosCallback qosCallback = new QosCallback() {
+        @Override
+        public void onError(@NonNull QosCallbackException exception) {
+            Log.e(LOG_TAG, "onError: " + exception.toString());
+            super.onError(exception);
+        }
+
+        @Override
+        public void onQosSessionAvailable(@NonNull QosSession session,
+                @NonNull QosSessionAttributes sessionAttributes) {
+            Log.d(LOG_TAG, "onQosSessionAvailable: " + session.toString() + ", "
+                    + sessionAttributes.toString());
+            super.onQosSessionAvailable(session, sessionAttributes);
+        }
+
+        @Override
+        public void onQosSessionLost(@NonNull QosSession session) {
+            Log.e(LOG_TAG, "onQosSessionLost: " + session.toString());
+            super.onQosSessionLost(session);
+        }
+    };
+
+    private void listenForBearer() {
+        try {
+            connectivityManager.registerQosCallback(new QosSocketInfo(network, socket),
+                    qosCallback, MoreExecutors.directExecutor());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     /**
@@ -110,6 +160,7 @@
         if (isOpen.getAndSet(false)) {
             output.flush();
         }
+        connectivityManager.unregisterQosCallback(qosCallback);
         socket.close();
     }
 
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
index 6813c91..ebccbde 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
@@ -402,10 +402,11 @@
     private void startMsrpSession(SimpleSdpMessage remoteSdp) {
         Log.d(TAG, "Start MSRP session: " + remoteSdp);
         if (remoteSdp.getAddress().isPresent() && remoteSdp.getPort().isPresent()) {
+            String localIp = getLocalIp();
             Futures.addCallback(
                     mMsrpManager.createMsrpSession(
-                            remoteSdp.getAddress().get(), remoteSdp.getPort().getAsInt(),
-                            this::receiveMsrpChunk),
+                            remoteSdp.getAddress().get(), remoteSdp.getPort().getAsInt(), localIp,
+                            0 /* localPort */, this::receiveMsrpChunk),
                     new FutureCallback<MsrpSession>() {
                         @Override
                         public void onSuccess(MsrpSession result) {
@@ -430,6 +431,11 @@
         }
     }
 
+    private String getLocalIp() {
+        SipSessionConfiguration configuration = mContext.getSipSession().getSessionConfiguration();
+        return configuration.getLocalIpAddress();
+    }
+
     private void receiveMsrpChunk(MsrpChunk chunk) {
         Log.d(TAG, "Received msrp= " + chunk + " conversation=" + mConversationId);
 
diff --git a/tests/src/com/android/phone/SimPhonebookProviderTest.java b/tests/src/com/android/phone/SimPhonebookProviderTest.java
index 8778529..4ab92a7 100644
--- a/tests/src/com/android/phone/SimPhonebookProviderTest.java
+++ b/tests/src/com/android/phone/SimPhonebookProviderTest.java
@@ -118,6 +118,14 @@
 
     @Test
     public void query_entityFiles_returnsCursorWithCorrectProjection() {
+        // Null projection
+        try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, null, null,
+                null)) {
+            assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList()
+                    .containsExactlyElementsIn(
+                            SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS);
+        }
+
         // Empty projection
         try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, new String[0], null,
                 null)) {
@@ -211,18 +219,38 @@
     }
 
     @Test
+    public void query_entityFilesItem_nullProjection_returnsCursorWithCorrectProjection() {
+        setupSimsWithSubscriptionIds(1);
+        mIccPhoneBook.makeAllEfsSupported(1);
+
+        // Null projection
+        try (Cursor cursor = mResolver.query(ElementaryFiles.getItemUri(1, EF_ADN), null, null,
+                null)) {
+            assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList()
+                    .containsExactlyElementsIn(
+                            SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS);
+        }
+    }
+
+    @Test
     public void query_adnRecords_returnsCursorWithMatchingProjection() {
         setupSimsWithSubscriptionIds(1);
         mIccPhoneBook.makeAllEfsSupported(1);
         Uri contentAdn = SimRecords.getContentUri(1, EF_ADN);
 
+        // Null projection
+        try (Cursor cursor = mResolver.query(contentAdn, null, null, null)) {
+            assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList()
+                    .containsExactlyElementsIn(SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS);
+        }
+
         // Empty projection
         try (Cursor cursor = mResolver.query(contentAdn, new String[0], null, null)) {
             assertThat(cursor).hasColumnNames();
         }
 
         // Single column
-        try (Cursor cursor = mResolver.query(contentAdn, new String[] {
+        try (Cursor cursor = mResolver.query(contentAdn, new String[]{
                 SimRecords.PHONE_NUMBER
         }, null, null)) {
             assertThat(cursor).hasColumnNames(SimRecords.PHONE_NUMBER);
@@ -531,6 +559,20 @@
     }
 
     @Test
+    public void query_itemUriNullProjection_returnsCursorWithAllColumns() {
+        setupSimsWithSubscriptionIds(1);
+        mIccPhoneBook.makeAllEfsSupported(1);
+
+        try (Cursor cursor = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1),
+                null, null, null)
+        ) {
+            assertThat(Objects.requireNonNull(
+                    cursor).getColumnNames()).asList().containsExactlyElementsIn(
+                    SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS);
+        }
+    }
+
+    @Test
     public void query_itemUriEmptyRecord_returnsEmptyCursor() {
         setupSimsWithSubscriptionIds(1);
         mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30);