Merge "Check for lock icon nullability" into qt-dev
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7828573..b37120f 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -79,10 +79,10 @@
     /** @hide */
     public static final String KEY_KILL_SIGNAL = "key_kill_signal";
 
-    IVoiceInteractor mInteractor;
+    @Nullable IVoiceInteractor mInteractor;
 
-    Context mContext;
-    Activity mActivity;
+    @Nullable Context mContext;
+    @Nullable Activity mActivity;
     boolean mRetaining;
 
     final HandlerCaller mHandlerCaller;
@@ -999,7 +999,9 @@
 
         // destroyed now
         mInteractor = null;
-        mActivity.setVoiceInteractor(null);
+        if (mActivity != null) {
+            mActivity.setVoiceInteractor(null);
+        }
     }
 
     public boolean submitRequest(Request request) {
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 64f8857..3900f16 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -231,6 +231,7 @@
         @SuppressWarnings("unchecked") // TODO(b/117779333): fix this warning
         final S castService = (S) this;
         mVultureCallback.onServiceDied(castService);
+        handleBindFailure();
     }
 
     // Note: we are dumping without a lock held so this is a bit racy but
@@ -406,7 +407,8 @@
             @NonNull BasePendingRequest<S, I> pendingRequest);
 
     /**
-     * Called if {@link Context#bindServiceAsUser} returns {@code false}.
+     * Called if {@link Context#bindServiceAsUser} returns {@code false}, or
+     * if {@link DeathRecipient#binderDied()} is called.
      */
     abstract void handleBindFailure();
 
@@ -431,8 +433,6 @@
             mBinding = false;
 
             if (!mServiceDied) {
-                // TODO(b/126266412): merge these 2 calls?
-                handleBindFailure();
                 handleBinderDied();
             }
         }
diff --git a/data/etc/com.android.dialer.xml b/data/etc/com.android.dialer.xml
index ccdb21f..405279f 100644
--- a/data/etc/com.android.dialer.xml
+++ b/data/etc/com.android.dialer.xml
@@ -24,5 +24,7 @@
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
         <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
+        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     </privapp-permissions>
 </permissions>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 11d635e..297153d 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -637,8 +637,7 @@
      * @see #setOrientation(Orientation)
      */
     public Orientation getOrientation() {
-        updateGradientStateOrientation();
-        return mGradientState.mOrientation;
+        return mGradientState.getOrientation();
     }
 
     /**
@@ -654,10 +653,7 @@
      * @see #getOrientation()
      */
     public void setOrientation(Orientation orientation) {
-        // Update the angle here so that subsequent attempts to obtain the orientation
-        // from the angle overwrite previously configured values during inflation
-        mGradientState.mAngle = getAngleFromOrientation(orientation);
-        mGradientState.mOrientation = orientation;
+        mGradientState.setOrientation(orientation);
         mGradientIsDirty = true;
         invalidateSelf();
     }
@@ -1246,76 +1242,6 @@
     }
 
     /**
-     * Update the orientation of the gradient based on the given angle only if the type is
-     * {@link #LINEAR_GRADIENT}
-     */
-    private void updateGradientStateOrientation() {
-        if (mGradientState.mGradient == LINEAR_GRADIENT) {
-            int angle = mGradientState.mAngle;
-            if (angle % 45 != 0) {
-                throw new IllegalArgumentException("Linear gradient requires 'angle' attribute to "
-                     + "be a multiple of 45");
-            }
-
-            Orientation orientation;
-            switch (angle) {
-                case 0:
-                    orientation = Orientation.LEFT_RIGHT;
-                    break;
-                case 45:
-                    orientation = Orientation.BL_TR;
-                    break;
-                case 90:
-                    orientation = Orientation.BOTTOM_TOP;
-                    break;
-                case 135:
-                    orientation = Orientation.BR_TL;
-                    break;
-                case 180:
-                    orientation = Orientation.RIGHT_LEFT;
-                    break;
-                case 225:
-                    orientation = Orientation.TR_BL;
-                    break;
-                case 270:
-                    orientation = Orientation.TOP_BOTTOM;
-                    break;
-                case 315:
-                    orientation = Orientation.TL_BR;
-                    break;
-                default:
-                    // Should not get here as exception is thrown above if angle is not multiple
-                    // of 45 degrees
-                    orientation = Orientation.LEFT_RIGHT;
-                    break;
-            }
-            mGradientState.mOrientation = orientation;
-        }
-    }
-
-    private int getAngleFromOrientation(Orientation orientation) {
-        switch (orientation) {
-            default:
-            case LEFT_RIGHT:
-                return 0;
-            case BL_TR:
-                return 45;
-            case BOTTOM_TOP:
-                return 90;
-            case BR_TL:
-                return 135;
-            case RIGHT_LEFT:
-                return 180;
-            case TR_BL:
-                return 225;
-            case TOP_BOTTOM:
-                return 270;
-            case TL_BR:
-                return 315;
-        }
-    }
-
-    /**
      * This checks mGradientIsDirty, and if it is true, recomputes both our drawing
      * rectangle (mRect) and the gradient itself, since it depends on our
      * rectangle too.
@@ -1344,8 +1270,7 @@
 
                 if (st.mGradient == LINEAR_GRADIENT) {
                     final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
-                    updateGradientStateOrientation();
-                    switch (st.mOrientation) {
+                    switch (st.getOrientation()) {
                     case TOP_BOTTOM:
                         x0 = r.left;            y0 = r.top;
                         x1 = x0;                y1 = level * r.bottom;
@@ -2056,7 +1981,7 @@
         int[] mAttrPadding;
 
         public GradientState(Orientation orientation, int[] gradientColors) {
-            mOrientation = orientation;
+            setOrientation(orientation);
             setGradientColors(gradientColors);
         }
 
@@ -2259,6 +2184,93 @@
             mCenterY = y;
         }
 
+        public void setOrientation(Orientation orientation) {
+            // Update the angle here so that subsequent attempts to obtain the orientation
+            // from the angle overwrite previously configured values during inflation
+            mAngle = getAngleFromOrientation(orientation);
+            mOrientation = orientation;
+        }
+
+        @NonNull
+        public Orientation getOrientation() {
+            updateGradientStateOrientation();
+            return mOrientation;
+        }
+
+        /**
+         * Update the orientation of the gradient based on the given angle only if the type is
+         * {@link #LINEAR_GRADIENT}
+         */
+        private void updateGradientStateOrientation() {
+            if (mGradient == LINEAR_GRADIENT) {
+                int angle = mAngle;
+                if (angle % 45 != 0) {
+                    throw new IllegalArgumentException("Linear gradient requires 'angle' attribute "
+                            + "to be a multiple of 45");
+                }
+
+                Orientation orientation;
+                switch (angle) {
+                    case 0:
+                        orientation = Orientation.LEFT_RIGHT;
+                        break;
+                    case 45:
+                        orientation = Orientation.BL_TR;
+                        break;
+                    case 90:
+                        orientation = Orientation.BOTTOM_TOP;
+                        break;
+                    case 135:
+                        orientation = Orientation.BR_TL;
+                        break;
+                    case 180:
+                        orientation = Orientation.RIGHT_LEFT;
+                        break;
+                    case 225:
+                        orientation = Orientation.TR_BL;
+                        break;
+                    case 270:
+                        orientation = Orientation.TOP_BOTTOM;
+                        break;
+                    case 315:
+                        orientation = Orientation.TL_BR;
+                        break;
+                    default:
+                        // Should not get here as exception is thrown above if angle is not multiple
+                        // of 45 degrees
+                        orientation = Orientation.LEFT_RIGHT;
+                        break;
+                }
+                mOrientation = orientation;
+            }
+        }
+
+        private int getAngleFromOrientation(@Nullable Orientation orientation) {
+            if (orientation != null) {
+                switch (orientation) {
+                    default:
+                    case LEFT_RIGHT:
+                        return 0;
+                    case BL_TR:
+                        return 45;
+                    case BOTTOM_TOP:
+                        return 90;
+                    case BR_TL:
+                        return 135;
+                    case RIGHT_LEFT:
+                        return 180;
+                    case TR_BL:
+                        return 225;
+                    case TOP_BOTTOM:
+                        return 270;
+                    case TL_BR:
+                        return 315;
+                }
+            } else {
+                return 0;
+            }
+        }
+
         public void setGradientColors(@Nullable int[] colors) {
             mGradientColors = colors;
             mSolidColors = null;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 62fd489..5173f63 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -167,8 +167,6 @@
     LOG_ALWAYS_FATAL_IF(physDeviceProperties.apiVersion < VK_MAKE_VERSION(1, 1, 0));
     mDriverVersion = physDeviceProperties.driverVersion;
 
-    mIsQualcomm = physDeviceProperties.vendorID == 20803;
-
     // query to get the initial queue props size
     uint32_t queueCount;
     mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 31de803..dd3c6d0 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -179,13 +179,6 @@
     SwapBehavior mSwapBehavior = SwapBehavior::Discard;
     GrVkExtensions mExtensions;
     uint32_t mDriverVersion = 0;
-
-    // TODO: Remove once fix has landed. Temporaryly needed for workaround for setting up AHB
-    // surfaces on Qualcomm. Currently if you don't use VkSwapchain Qualcomm is not setting
-    // reporting that we need to use one of their private vendor usage bits which greatly effects
-    // performance if it is not used.
-    bool mIsQualcomm = false;
-    bool isQualcomm() const { return mIsQualcomm; }
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index df6b9ed..b2cc23e 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -297,11 +297,6 @@
     native_window_get_consumer_usage(window, &consumerUsage);
     windowInfo.windowUsageFlags = consumerUsage | hwbUsage.androidHardwareBufferUsage;
 
-    if (vkManager.isQualcomm()) {
-        windowInfo.windowUsageFlags =
-                windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
-    }
-
     /*
      * Now we attempt to modify the window!
      */
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 5de56c7..b3c2bb7 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -52,6 +52,7 @@
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Objects;
 import java.util.function.ToIntFunction;
 
 /**
@@ -369,10 +370,12 @@
             // If we're okay with something larger than native format, just
             // return a frame without up-scaling it
             if (size.getWidth() > width && size.getHeight() > height) {
-                return mmr.getFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC);
+                return Objects.requireNonNull(
+                        mmr.getFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC));
             } else {
-                return mmr.getScaledFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC,
-                        size.getWidth(), size.getHeight());
+                return Objects.requireNonNull(
+                        mmr.getScaledFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC,
+                        size.getWidth(), size.getHeight()));
             }
         } catch (RuntimeException e) {
             throw new IOException("Failed to create thumbnail", e);
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 376999d..beb0e47 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -107,9 +107,11 @@
         EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName());
 
         mIntent.setComponent(componentName);
-        mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
-                AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
-                Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
+        synchronized (mService) {
+            mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
+                    AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
+                    Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 696697e..b394eea 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1658,23 +1658,15 @@
         app.killed = false;
         final long startSeq = app.startSeq = ++mProcStartSeqCounter;
         app.setStartParams(uid, hostingRecord, seInfo, startTime);
+        app.setUsingWrapper(invokeWith != null
+                || SystemProperties.get("wrap." + app.processName) != null);
+        mPendingStarts.put(startSeq, app);
+
         if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
             if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
                     "Posting procStart msg for " + app.toShortString());
             mService.mProcStartHandler.post(() -> {
                 try {
-                    synchronized (mService) {
-                        final String reason = isProcStartValidLocked(app, startSeq);
-                        if (reason != null) {
-                            Slog.w(TAG_PROCESSES, app + " not valid anymore,"
-                                    + " don't start process, " + reason);
-                            app.pendingStart = false;
-                            return;
-                        }
-                        app.setUsingWrapper(invokeWith != null
-                                || SystemProperties.get("wrap." + app.processName) != null);
-                        mPendingStarts.put(startSeq, app);
-                    }
                     final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
                             entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
                             app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index eecbb16..35a82ae 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1626,6 +1626,15 @@
     }
 
     /**
+     * Maximum time buffer in which JobScheduler will try to optimize periodic job scheduling. This
+     * does not cause a job's period to be larger than requested (eg: if the requested period is
+     * shorter than this buffer). This is used to put a limit on when JobScheduler will intervene
+     * and try to optimize scheduling if the current job finished less than this amount of time to
+     * the start of the next period
+     */
+    private static final long PERIODIC_JOB_WINDOW_BUFFER = 30 * MINUTE_IN_MILLIS;
+
+    /**
      * Called after a periodic has executed so we can reschedule it. We take the last execution
      * time of the job to be the time of completion (i.e. the time at which this function is
      * called).
@@ -1645,16 +1654,18 @@
         final long period = periodicToReschedule.getJob().getIntervalMillis();
         final long latestRunTimeElapsed = periodicToReschedule.getOriginalLatestRunTimeElapsed();
         final long flex = periodicToReschedule.getJob().getFlexMillis();
+        long rescheduleBuffer = 0;
 
+        final long diffMs = Math.abs(elapsedNow - latestRunTimeElapsed);
         if (elapsedNow > latestRunTimeElapsed) {
             // The job ran past its expected run window. Have it count towards the current window
             // and schedule a new job for the next window.
             if (DEBUG) {
                 Slog.i(TAG, "Periodic job ran after its intended window.");
             }
-            final long diffMs = (elapsedNow - latestRunTimeElapsed);
             int numSkippedWindows = (int) (diffMs / period) + 1; // +1 to include original window
-            if (period != flex && diffMs > Math.min(30 * MINUTE_IN_MILLIS, (period - flex) / 2)) {
+            if (period != flex && diffMs > Math.min(PERIODIC_JOB_WINDOW_BUFFER,
+                    (period - flex) / 2)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Custom flex job ran too close to next window.");
                 }
@@ -1665,9 +1676,15 @@
             newLatestRuntimeElapsed = latestRunTimeElapsed + (period * numSkippedWindows);
         } else {
             newLatestRuntimeElapsed = latestRunTimeElapsed + period;
+            if (diffMs < PERIODIC_JOB_WINDOW_BUFFER && diffMs < period / 6) {
+                // Add a little buffer to the start of the next window so the job doesn't run
+                // too soon after this completed one.
+                rescheduleBuffer = Math.min(PERIODIC_JOB_WINDOW_BUFFER, period / 6 - diffMs);
+            }
         }
 
-        final long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
+        final long newEarliestRunTimeElapsed = newLatestRuntimeElapsed
+                - Math.min(flex, period - rescheduleBuffer);
 
         if (DEBUG) {
             Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index bd6662d..aa51aec 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -317,8 +317,10 @@
         if (configManager == null) {
             return;
         }
-        PersistableBundle configs = configManager.getConfigForSubId(
-                SubscriptionManager.getDefaultDataSubscriptionId());
+
+        int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        PersistableBundle configs = SubscriptionManager.isValidSubscriptionId(ddSubId)
+                ? configManager.getConfigForSubId(ddSubId) : null;
         if (configs == null) {
             if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
             configs = CarrierConfigManager.getDefaultConfig();
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5b7eca6..b2315c7 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -60,7 +60,6 @@
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
-import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
@@ -75,6 +74,7 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 import com.android.internal.location.gnssmetrics.GnssMetrics;
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
 
@@ -184,7 +184,6 @@
     private static final int DOWNLOAD_PSDS_DATA = 6;
     private static final int UPDATE_LOCATION = 7;  // Handle external location from network listener
     private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11;
-    private static final int SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED = 12;
     private static final int INITIALIZE_HANDLER = 13;
     private static final int REQUEST_LOCATION = 16;
     private static final int REPORT_LOCATION = 17; // HAL reports location
@@ -484,22 +483,13 @@
                     updateLowPowerMode();
                     break;
                 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
+                case TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
                     subscriptionOrCarrierConfigChanged(context);
                     break;
             }
         }
     };
 
-    // TODO: replace OnSubscriptionsChangedListener with ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
-    //       broadcast receiver.
-    private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
-            new OnSubscriptionsChangedListener() {
-                @Override
-                public void onSubscriptionsChanged() {
-                    sendMessage(SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED, 0, null);
-                }
-            };
-
     /**
      * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
      */
@@ -515,12 +505,15 @@
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
         CarrierConfigManager configManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        String mccMnc = phone.getSimOperator();
+        int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        String mccMnc = SubscriptionManager.isValidSubscriptionId(ddSubId)
+                ? phone.getSimOperator(ddSubId) : phone.getSimOperator();
         boolean isKeepLppProfile = false;
         if (!TextUtils.isEmpty(mccMnc)) {
             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
             if (configManager != null) {
-                PersistableBundle b = configManager.getConfig();
+                PersistableBundle b = SubscriptionManager.isValidSubscriptionId(ddSubId)
+                        ? configManager.getConfigForSubId(ddSubId) : null;
                 if (b != null) {
                     isKeepLppProfile =
                             b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL);
@@ -539,7 +532,6 @@
                 SystemProperties.set(GnssConfiguration.LPP_PROFILE, "");
             }
             reloadGpsProperties();
-            mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
         } else {
             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
         }
@@ -577,9 +569,9 @@
         mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
         mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
         mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
+        mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
         if (mGnssVisibilityControl != null) {
-            mGnssVisibilityControl.updateProxyApps(mGnssConfiguration.getProxyApps());
-            mGnssVisibilityControl.setEsNotify(mGnssConfiguration.getEsNotify(0));
+            mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration);
         }
     }
 
@@ -1892,28 +1884,34 @@
         TelephonyManager phone = (TelephonyManager)
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
         int type = AGPS_SETID_TYPE_NONE;
-        String data = "";
+        String setId = null;
 
+        int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
-            String data_temp = phone.getSubscriberId();
-            if (data_temp == null) {
-                // This means the framework does not have the SIM card ready.
-            } else {
+            if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+                setId = phone.getSubscriberId(ddSubId);
+            }
+            if (setId == null) {
+                setId = phone.getSubscriberId();
+            }
+            if (setId != null) {
                 // This means the framework has the SIM card.
-                data = data_temp;
                 type = AGPS_SETID_TYPE_IMSI;
             }
         } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
-            String data_temp = phone.getLine1Number();
-            if (data_temp == null) {
-                // This means the framework does not have the SIM card ready.
-            } else {
+            if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+                setId = phone.getLine1Number(ddSubId);
+            }
+            if (setId == null) {
+                setId = phone.getLine1Number();
+            }
+            if (setId != null) {
                 // This means the framework has the SIM card.
-                data = data_temp;
                 type = AGPS_SETID_TYPE_MSISDN;
             }
         }
-        native_agps_set_id(type, data);
+
+        native_agps_set_id(type, (setId == null) ? "" : setId);
     }
 
     @NativeEntryPoint
@@ -2025,9 +2023,6 @@
                 case UPDATE_LOCATION:
                     handleUpdateLocation((Location) msg.obj);
                     break;
-                case SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED:
-                    subscriptionOrCarrierConfigChanged(mContext);
-                    break;
                 case INITIALIZE_HANDLER:
                     handleInitialize();
                     break;
@@ -2066,17 +2061,6 @@
             // (this configuration might change in the future based on SIM changes)
             reloadGpsProperties();
 
-            // TODO: When this object "finishes" we should unregister by invoking
-            // SubscriptionManager.getInstance(mContext).unregister
-            // (mOnSubscriptionsChangedListener);
-            // This is not strictly necessary because it will be unregistered if the
-            // notification fails but it is good form.
-
-            // Register for SubscriptionInfo list changes which is guaranteed
-            // to invoke onSubscriptionsChanged the first time.
-            SubscriptionManager.from(mContext)
-                    .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
-
             // listen for events
             IntentFilter intentFilter = new IntentFilter();
             intentFilter.addAction(ALARM_WAKEUP);
@@ -2086,6 +2070,7 @@
             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
             intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+            intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
             mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
 
             mNetworkConnectivityHandler.registerNetworkCallbacks();
@@ -2164,8 +2149,6 @@
                 return "DOWNLOAD_PSDS_DATA_FINISHED";
             case UPDATE_LOCATION:
                 return "UPDATE_LOCATION";
-            case SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED:
-                return "SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED";
             case INITIALIZE_HANDLER:
                 return "INITIALIZE_HANDLER";
             case REPORT_LOCATION:
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index a3670a4..c49d900 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -76,7 +76,7 @@
     private final GpsNetInitiatedHandler mNiHandler;
 
     private boolean mIsGpsEnabled;
-    private volatile boolean mEsNotify;
+    private boolean mEsNotify;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
     private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -124,10 +124,6 @@
         }
     }
 
-    void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
-        runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
-    }
-
     void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
             String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
             boolean inEmergencyMode, boolean isCachedLocation) {
@@ -136,15 +132,25 @@
                         requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
     }
 
-    void setEsNotify(int esNotifyConfig) {
-        if (esNotifyConfig != ES_NOTIFY_NONE && esNotifyConfig != ES_NOTIFY_ALL) {
+    void onConfigurationUpdated(GnssConfiguration configuration) {
+        // The configuration object must be accessed only in the caller thread and not in mHandler.
+        List<String> nfwLocationAccessProxyApps = configuration.getProxyApps();
+        int esNotify = configuration.getEsNotify(ES_NOTIFY_NONE);
+        runOnHandler(() -> {
+            setEsNotify(esNotify);
+            handleUpdateProxyApps(nfwLocationAccessProxyApps);
+        });
+    }
+
+    private void setEsNotify(int esNotify) {
+        if (esNotify != ES_NOTIFY_NONE && esNotify != ES_NOTIFY_ALL) {
             Log.e(TAG, "Config parameter " + GnssConfiguration.CONFIG_ES_NOTIFY_INT
-                    + " is set to invalid value: " + esNotifyConfig
+                    + " is set to invalid value: " + esNotify
                     + ". Using default value: " + ES_NOTIFY_NONE);
-            esNotifyConfig = ES_NOTIFY_NONE;
+            esNotify = ES_NOTIFY_NONE;
         }
 
-        mEsNotify = (esNotifyConfig == ES_NOTIFY_ALL);
+        mEsNotify = (esNotify == ES_NOTIFY_ALL);
     }
 
     private void handleInitialize() {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 37c1aaa..b2ba290 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -929,6 +929,7 @@
                 final BasePermission bp = mSettings.getPermissionLocked(permName);
                 final boolean appSupportsRuntimePermissions =
                         pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+                String upgradedActivityRecognitionPermission = null;
 
                 if (DEBUG_INSTALL) {
                     Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);
@@ -947,11 +948,40 @@
                 // Cache newImplicitPermissions before modifing permissionsState as for the shared
                 // uids the original and new state are the same object
                 if (!origPermissions.hasRequestedPermission(permName)
-                        && pkg.implicitPermissions.contains(permName)) {
-                    newImplicitPermissions.add(permName);
+                        && (pkg.implicitPermissions.contains(permName)
+                                || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
+                    if (pkg.implicitPermissions.contains(permName)) {
+                        // If permName is an implicit permission, try to auto-grant
+                        newImplicitPermissions.add(permName);
 
-                    if (DEBUG_PERMISSIONS) {
-                        Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+                        if (DEBUG_PERMISSIONS) {
+                            Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+                        }
+                    } else {
+                        // Special case for Activity Recognition permission. Even if AR permission
+                        // is not an implicit permission we want to add it to the list (try to
+                        // auto-grant it) if the app was installed on a device before AR permission
+                        // was split, regardless of if the app now requests the new AR permission
+                        // or has updated its target SDK and AR is no longer implicit to it.
+                        // This is a compatibility workaround for apps when AR permission was
+                        // split in Q.
+                        int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+                        for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+                            PermissionManager.SplitPermissionInfo sp =
+                                    PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+                            String splitPermName = sp.getSplitPermission();
+                            if (sp.getNewPermissions().contains(permName)
+                                    && origPermissions.hasInstallPermission(splitPermName)) {
+                                upgradedActivityRecognitionPermission = splitPermName;
+                                newImplicitPermissions.add(permName);
+
+                                if (DEBUG_PERMISSIONS) {
+                                    Slog.i(TAG, permName + " is newly added for "
+                                            + pkg.packageName);
+                                }
+                                break;
+                            }
+                        }
                     }
                 }
 
@@ -985,7 +1015,8 @@
                     // For all apps normal permissions are install time ones.
                     grant = GRANT_INSTALL;
                 } else if (bp.isRuntime()) {
-                    if (origPermissions.hasInstallPermission(bp.getName())) {
+                    if (origPermissions.hasInstallPermission(bp.getName())
+                            || upgradedActivityRecognitionPermission != null) {
                         // Before Q we represented some runtime permissions as install permissions,
                         // in Q we cannot do this anymore. Hence upgrade them all.
                         grant = GRANT_UPGRADE;
@@ -1161,10 +1192,15 @@
                                     .getInstallPermissionState(perm);
                             int flags = (permState != null) ? permState.getFlags() : 0;
 
+                            BasePermission bpToRevoke =
+                                    upgradedActivityRecognitionPermission == null
+                                    ? bp : mSettings.getPermissionLocked(
+                                            upgradedActivityRecognitionPermission);
                             // Remove install permission
-                            if (origPermissions.revokeInstallPermission(bp)
+                            if (origPermissions.revokeInstallPermission(bpToRevoke)
                                     != PERMISSION_OPERATION_FAILURE) {
-                                origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
+                                origPermissions.updatePermissionFlags(bpToRevoke,
+                                        UserHandle.USER_ALL,
                                         (MASK_PERMISSION_FLAGS_ALL
                                                 & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
                                 changedInstallPermission = true;
@@ -1489,9 +1525,11 @@
                     for (int userNum = 0; userNum < numUsers; userNum++) {
                         int userId = users[userNum];
 
-                        ps.updatePermissionFlags(bp, userId,
-                                FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
-                                FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+                        if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
+                            ps.updatePermissionFlags(bp, userId,
+                                    FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+                                    FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+                        }
                         updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
 
                         boolean inheritsFromInstallPerm = false;
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index f7edf65..18c524a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -183,15 +183,188 @@
         assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
 
-        advanceElapsedClock(45 * MINUTE_IN_MILLIS); // now + 55 minutes
+        advanceElapsedClock(20 * MINUTE_IN_MILLIS); // now + 30 minutes
 
         rescheduledJob = mService.getRescheduleJobForPeriodic(job);
         assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
 
+        advanceElapsedClock(25 * MINUTE_IN_MILLIS); // now + 55 minutes
+
+        rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        // Shifted because it's close to the end of the window.
+        assertEquals(nextWindowStartTime + 5 * MINUTE_IN_MILLIS,
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
         advanceElapsedClock(4 * MINUTE_IN_MILLIS); // now + 59 minutes
 
         rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+        // Shifted because it's close to the end of the window.
+        assertEquals(nextWindowStartTime + 9 * MINUTE_IN_MILLIS,
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+    }
+
+    /**
+     * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+     * with an extra delay and correct deadline constraint if the periodic job is completed near the
+     * end of its expected running window.
+     */
+    @Test
+    public void testGetRescheduleJobForPeriodic_closeToEndOfWindow() {
+        JobStatus frequentJob = createJobStatus(
+                "testGetRescheduleJobForPeriodic_closeToEndOfWindow",
+                createJobInfo().setPeriodic(15 * MINUTE_IN_MILLIS));
+        long now = sElapsedRealtimeClock.millis();
+        long nextWindowStartTime = now + 15 * MINUTE_IN_MILLIS;
+        long nextWindowEndTime = now + 30 * MINUTE_IN_MILLIS;
+
+        // At the beginning of the window. Next window should be unaffected.
+        JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(frequentJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Halfway through window. Next window should be unaffected.
+        advanceElapsedClock((long) (7.5 * MINUTE_IN_MILLIS));
+        rescheduledJob = mService.getRescheduleJobForPeriodic(frequentJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window start time should be shifted slightly.
+        advanceElapsedClock(6 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(frequentJob);
+        assertEquals(nextWindowStartTime + MINUTE_IN_MILLIS,
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        JobStatus mediumJob = createJobStatus("testGetRescheduleJobForPeriodic_closeToEndOfWindow",
+                createJobInfo().setPeriodic(HOUR_IN_MILLIS));
+        now = sElapsedRealtimeClock.millis();
+        nextWindowStartTime = now + HOUR_IN_MILLIS;
+        nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+
+        // At the beginning of the window. Next window should be unaffected.
+        rescheduledJob = mService.getRescheduleJobForPeriodic(mediumJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Halfway through window. Next window should be unaffected.
+        advanceElapsedClock(30 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(mediumJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // At the edge 1/6 of window. Next window should be unaffected.
+        advanceElapsedClock(20 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(mediumJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window start time should be shifted slightly.
+        advanceElapsedClock(6 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(mediumJob);
+        assertEquals(nextWindowStartTime + (6 * MINUTE_IN_MILLIS),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        JobStatus longJob = createJobStatus("testGetRescheduleJobForPeriodic_closeToEndOfWindow",
+                createJobInfo().setPeriodic(6 * HOUR_IN_MILLIS));
+        now = sElapsedRealtimeClock.millis();
+        nextWindowStartTime = now + 6 * HOUR_IN_MILLIS;
+        nextWindowEndTime = now + 12 * HOUR_IN_MILLIS;
+
+        // At the beginning of the window. Next window should be unaffected.
+        rescheduledJob = mService.getRescheduleJobForPeriodic(longJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Halfway through window. Next window should be unaffected.
+        advanceElapsedClock(3 * HOUR_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(longJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // At the edge 1/6 of window. Next window should be unaffected.
+        advanceElapsedClock(2 * HOUR_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(longJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window should be unaffected since we're over the shift cap.
+        advanceElapsedClock(15 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(longJob);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window start time should be shifted slightly.
+        advanceElapsedClock(30 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(longJob);
+        assertEquals(nextWindowStartTime + (30 * MINUTE_IN_MILLIS),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Flex duration close to period duration.
+        JobStatus gameyFlex = createJobStatus("testGetRescheduleJobForPeriodic_closeToEndOfWindow",
+                createJobInfo().setPeriodic(HOUR_IN_MILLIS, 59 * MINUTE_IN_MILLIS));
+        now = sElapsedRealtimeClock.millis();
+        nextWindowStartTime = now + HOUR_IN_MILLIS + MINUTE_IN_MILLIS;
+        nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+
+        // At the beginning of the window. Next window should be unaffected.
+        rescheduledJob = mService.getRescheduleJobForPeriodic(gameyFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Halfway through window. Next window should be unaffected.
+        advanceElapsedClock(29 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(gameyFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // At the edge 1/6 of window. Next window should be unaffected.
+        advanceElapsedClock(20 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(gameyFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window start time should be shifted slightly.
+        advanceElapsedClock(6 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(gameyFlex);
+        assertEquals(nextWindowStartTime + (5 * MINUTE_IN_MILLIS),
+                rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Very short flex duration compared to period duration.
+        JobStatus superFlex = createJobStatus("testGetRescheduleJobForPeriodic_closeToEndOfWindow",
+                createJobInfo().setPeriodic(HOUR_IN_MILLIS, 10 * MINUTE_IN_MILLIS));
+        now = sElapsedRealtimeClock.millis();
+        nextWindowStartTime = now + HOUR_IN_MILLIS + 50 * MINUTE_IN_MILLIS;
+        nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+
+        // At the beginning of the window. Next window should be unaffected.
+        rescheduledJob = mService.getRescheduleJobForPeriodic(superFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // Halfway through window. Next window should be unaffected.
+        advanceElapsedClock(29 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(superFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // At the edge 1/6 of window. Next window should be unaffected.
+        advanceElapsedClock(20 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(superFlex);
+        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+        // In last 1/6 of window. Next window should be unaffected since the flex duration pushes
+        // the next window start time far enough away.
+        advanceElapsedClock(6 * MINUTE_IN_MILLIS);
+        rescheduledJob = mService.getRescheduleJobForPeriodic(superFlex);
         assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
     }
@@ -265,7 +438,9 @@
         advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 55 minutes
 
         rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
-        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        // Shifted because it's close to the end of the window.
+        assertEquals(nextWindowStartTime + 5 * MINUTE_IN_MILLIS,
+                rescheduledJob.getEarliestRunTime());
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
 
         advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 57 minutes
@@ -273,7 +448,9 @@
         advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 59 minutes
 
         rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
-        assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+        // Shifted because it's close to the end of the window.
+        assertEquals(nextWindowStartTime + 9 * MINUTE_IN_MILLIS,
+                rescheduledJob.getEarliestRunTime());
         assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
     }
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 93c1b21..eefaf47 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1451,6 +1451,9 @@
      * foreground call is ended.
      * <p>
      * Requires permission {@link android.Manifest.permission#ANSWER_PHONE_CALLS}.
+     * <p>
+     * Note: this method CANNOT be used to end ongoing emergency calls and will return {@code false}
+     * if an attempt is made to end an emergency call.
      *
      * @return {@code true} if there is a call which will be rejected or terminated, {@code false}
      * otherwise.
@@ -1458,8 +1461,6 @@
      * instead.  Apps performing call screening should use the {@link CallScreeningService} API
      * instead.
      */
-
-
     @RequiresPermission(Manifest.permission.ANSWER_PHONE_CALLS)
     @Deprecated
     public boolean endCall() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d00341b..6ba359b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -836,13 +836,6 @@
             "carrier_metered_roaming_apn_types_strings";
 
     /**
-     * Default APN types that are metered on IWLAN by the carrier
-     * @hide
-     */
-    public static final String KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS =
-            "carrier_metered_iwlan_apn_types_strings";
-
-    /**
      * CDMA carrier ERI (Enhanced Roaming Indicator) file name
      * @hide
      */
@@ -3116,15 +3109,6 @@
                 new String[]{"default", "mms", "dun", "supl"});
         sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{"default", "mms", "dun", "supl"});
-        // By default all APNs should be unmetered if the device is on IWLAN. However, we add
-        // default APN as metered here as a workaround for P because in some cases, a data
-        // connection was brought up on cellular, but later on the device camped on IWLAN. That
-        // data connection was incorrectly treated as unmetered due to the current RAT IWLAN.
-        // Marking it as metered for now can workaround the issue.
-        // Todo: This will be fixed in Q when IWLAN full refactoring is completed.
-        sDefaults.putStringArray(KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
-                new String[]{"default"});
-
         sDefaults.putIntArray(KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY,
                 new int[]{
                     4, /* IS95A */
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index a86fda4..a78bae4 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1273,6 +1273,23 @@
     }
 
     /**
+     * Get supported APN types
+     *
+     * @return list of APN types
+     * @hide
+     */
+    @ApnType
+    public List<Integer> getApnTypes() {
+        List<Integer> types = new ArrayList<>();
+        for (Integer type : APN_TYPE_INT_MAP.keySet()) {
+            if ((mApnTypeBitmask & type) == type) {
+                types.add(type);
+            }
+        }
+        return types;
+    }
+
+    /**
      * @param apnTypeBitmask bitmask of APN types.
      * @return comma delimited list of APN types.
      * @hide