Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3b3a5fa authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Close tethering when UI entitlement fails"

parents 6bd5cf2b 29b7014d
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -233,6 +233,10 @@ public class Tethering extends BaseNetworkObserver {
        // permission is changed according to entitlement check result.
        // permission is changed according to entitlement check result.
        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
            mLog.log("OBSERVED UiEnitlementFailed");
            stopTethering(downstream);
        });


        mCarrierConfigChange = new VersionedBroadcastListener(
        mCarrierConfigChange = new VersionedBroadcastListener(
                "CarrierConfigChangeListener", mContext, mHandler, filter,
                "CarrierConfigChangeListener", mContext, mHandler, filter,
+26 −4
Original line number Original line Diff line number Diff line
@@ -109,6 +109,7 @@ public class EntitlementManager {
    private boolean mCellularUpstreamPermitted = true;
    private boolean mCellularUpstreamPermitted = true;
    private boolean mUsingCellularAsUpstream = false;
    private boolean mUsingCellularAsUpstream = false;
    private boolean mNeedReRunProvisioningUi = false;
    private boolean mNeedReRunProvisioningUi = false;
    private OnUiEntitlementFailedListener mListener;


    public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
    public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
            int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
            int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
@@ -129,6 +130,20 @@ public class EntitlementManager {
                null, mHandler);
                null, mHandler);
    }
    }


    public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
        mListener = listener;
    }

    /** Callback fired when UI entitlement failed. */
    public interface OnUiEntitlementFailedListener {
        /**
         * Ui entitlement check fails in |downstream|.
         *
         * @param downstream  tethering type from ConnectivityManager.TETHERING_{@code *}.
         */
        void onUiEntitlementFailed(int downstream);
    }

    /**
    /**
     * Pass a new TetheringConfiguration instance each time when
     * Pass a new TetheringConfiguration instance each time when
     * Tethering#updateConfiguration() is called.
     * Tethering#updateConfiguration() is called.
@@ -337,7 +352,9 @@ public class EntitlementManager {
     */
     */
    protected void runSilentTetherProvisioning(int type) {
    protected void runSilentTetherProvisioning(int type) {
        if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
        if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
        ResultReceiver receiver = buildProxyReceiver(type, null);
        // For silent provisioning, settings would stop tethering when entitlement fail.
        ResultReceiver receiver = buildProxyReceiver(type,
                false/* notifyFail */, null);


        Intent intent = new Intent();
        Intent intent = new Intent();
        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -358,7 +375,8 @@ public class EntitlementManager {
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    protected void runUiTetherProvisioning(int type) {
    protected void runUiTetherProvisioning(int type) {
        ResultReceiver receiver = buildProxyReceiver(type, null);
        ResultReceiver receiver = buildProxyReceiver(type,
                true/* notifyFail */, null);
        runUiTetherProvisioning(type, receiver);
        runUiTetherProvisioning(type, receiver);
    }
    }


@@ -555,12 +573,16 @@ public class EntitlementManager {
        }
        }
    }
    }


    private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
    private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
            final ResultReceiver receiver) {
        ResultReceiver rr = new ResultReceiver(mHandler) {
        ResultReceiver rr = new ResultReceiver(mHandler) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
                int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
                addDownstreamMapping(type, updatedCacheValue);
                addDownstreamMapping(type, updatedCacheValue);
                if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
                    mListener.onUiEntitlementFailed(type);
                }
                if (receiver != null) receiver.send(updatedCacheValue, null);
                if (receiver != null) receiver.send(updatedCacheValue, null);
            }
            }
        };
        };
@@ -627,7 +649,7 @@ public class EntitlementManager {
        if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
        if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
            receiver.send(cacheValue, null);
            receiver.send(cacheValue, null);
        } else {
        } else {
            ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
            ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
            runUiTetherProvisioning(downstream, proxy);
            runUiTetherProvisioning(downstream, proxy);
        }
        }
    }
    }
+73 −45
Original line number Original line Diff line number Diff line
@@ -31,6 +31,8 @@ import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


import android.content.ContentResolver;
import android.content.ContentResolver;
@@ -80,6 +82,7 @@ public final class EntitlementManagerTest {
    @Mock private MockableSystemProperties mSystemProperties;
    @Mock private MockableSystemProperties mSystemProperties;
    @Mock private Resources mResources;
    @Mock private Resources mResources;
    @Mock private SharedLog mLog;
    @Mock private SharedLog mLog;
    @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;


    // Like so many Android system APIs, these cannot be mocked because it is marked final.
    // Like so many Android system APIs, these cannot be mocked because it is marked final.
    // We have to use the real versions.
    // We have to use the real versions.
@@ -109,7 +112,6 @@ public final class EntitlementManagerTest {


    public class WrappedEntitlementManager extends EntitlementManager {
    public class WrappedEntitlementManager extends EntitlementManager {
        public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
        public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
        public boolean everRunUiEntitlement = false;
        public int uiProvisionCount = 0;
        public int uiProvisionCount = 0;
        public int silentProvisionCount = 0;
        public int silentProvisionCount = 0;


@@ -118,20 +120,22 @@ public final class EntitlementManagerTest {
            super(ctx, target, log, what, systemProperties);
            super(ctx, target, log, what, systemProperties);
        }
        }


        @Override
        public void reset() {
        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
            everRunUiEntitlement = true;
            uiProvisionCount = 0;
            receiver.send(fakeEntitlementResult, null);
            silentProvisionCount = 0;
        }
        }


        @Override
        @Override
        protected void runUiTetherProvisioning(int type) {
        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
            uiProvisionCount++;
            uiProvisionCount++;
            receiver.send(fakeEntitlementResult, null);
        }
        }


        @Override
        @Override
        protected void runSilentTetherProvisioning(int type) {
        protected void runSilentTetherProvisioning(int type) {
            silentProvisionCount++;
            silentProvisionCount++;
            addDownstreamMapping(type, fakeEntitlementResult);
        }
        }
    }
    }


@@ -157,6 +161,7 @@ public final class EntitlementManagerTest {
        mSM = new TestStateMachine();
        mSM = new TestStateMachine();
        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
                mSystemProperties);
                mSystemProperties);
        mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
        mEnMgr.updateConfiguration(
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
    }
    }
@@ -246,7 +251,6 @@ public final class EntitlementManagerTest {
        final CountDownLatch mCallbacklatch = new CountDownLatch(1);
        final CountDownLatch mCallbacklatch = new CountDownLatch(1);
        // 1. Entitlement check is not required.
        // 1. Entitlement check is not required.
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.everRunUiEntitlement = false;
        ResultReceiver receiver = new ResultReceiver(null) {
        ResultReceiver receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -257,13 +261,13 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertFalse(mEnMgr.everRunUiEntitlement);
        assertEquals(0, mEnMgr.uiProvisionCount);
        mEnMgr.reset();


        setupForRequiredProvisioning();
        setupForRequiredProvisioning();
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                  INVALID_SUBSCRIPTION_ID));
                  INVALID_SUBSCRIPTION_ID));
        // 2. No cache value and don't need to run entitlement check.
        // 2. No cache value and don't need to run entitlement check.
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -274,10 +278,10 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertFalse(mEnMgr.everRunUiEntitlement);
        assertEquals(0, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
        // 3. No cache value and ui entitlement check is needed.
        // 3. No cache value and ui entitlement check is needed.
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -288,10 +292,10 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertTrue(mEnMgr.everRunUiEntitlement);
        assertEquals(1, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
        // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
        // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -302,10 +306,10 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertFalse(mEnMgr.everRunUiEntitlement);
        assertEquals(0, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
        // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
        // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -316,10 +320,10 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertTrue(mEnMgr.everRunUiEntitlement);
        assertEquals(1, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
        // 6. Cache value is TETHER_ERROR_NO_ERROR.
        // 6. Cache value is TETHER_ERROR_NO_ERROR.
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -330,9 +334,9 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertFalse(mEnMgr.everRunUiEntitlement);
        assertEquals(0, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
        // 7. Test get value for other downstream type.
        // 7. Test get value for other downstream type.
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
        receiver = new ResultReceiver(null) {
            @Override
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -343,7 +347,8 @@ public final class EntitlementManagerTest {
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        callbackTimeoutHelper(mCallbacklatch);
        callbackTimeoutHelper(mCallbacklatch);
        assertFalse(mEnMgr.everRunUiEntitlement);
        assertEquals(0, mEnMgr.uiProvisionCount);
        mEnMgr.reset();
    }
    }


    void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
    void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -358,15 +363,15 @@ public final class EntitlementManagerTest {
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                  INVALID_SUBSCRIPTION_ID));
                  INVALID_SUBSCRIPTION_ID));
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
    }
    }


@@ -376,17 +381,17 @@ public final class EntitlementManagerTest {
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                  INVALID_SUBSCRIPTION_ID));
                  INVALID_SUBSCRIPTION_ID));
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
        assertFalse(mEnMgr.isCellularUpstreamPermitted());
    }
    }


@@ -396,14 +401,14 @@ public final class EntitlementManagerTest {
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                  INVALID_SUBSCRIPTION_ID));
                  INVALID_SUBSCRIPTION_ID));
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
@@ -417,48 +422,71 @@ public final class EntitlementManagerTest {
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                INVALID_SUBSCRIPTION_ID));
                INVALID_SUBSCRIPTION_ID));
        // 1. start ui provisioning, upstream is mobile
        // 1. start ui provisioning, upstream is mobile
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        assertTrue(mEnMgr.uiProvisionCount == 1);
        assertEquals(1, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.silentProvisionCount == 0);
        assertEquals(0, mEnMgr.silentProvisionCount);
        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.reset();
        // 2. start no-ui provisioning
        // 2. start no-ui provisioning
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        assertTrue(mEnMgr.silentProvisionCount == 1);
        assertEquals(0, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.uiProvisionCount == 1);
        assertEquals(1, mEnMgr.silentProvisionCount);
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.reset();
        // 3. tear down mobile, then start ui provisioning
        // 3. tear down mobile, then start ui provisioning
        mEnMgr.notifyUpstream(false);
        mEnMgr.notifyUpstream(false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        assertTrue(mEnMgr.uiProvisionCount == 1);
        assertEquals(0, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.silentProvisionCount == 1);
        assertEquals(0, mEnMgr.silentProvisionCount);
        mEnMgr.reset();
        // 4. switch upstream back to mobile
        // 4. switch upstream back to mobile
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        assertTrue(mEnMgr.uiProvisionCount == 2);
        assertEquals(1, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.silentProvisionCount == 1);
        assertEquals(0, mEnMgr.silentProvisionCount);
        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
        assertTrue(mEnMgr.isCellularUpstreamPermitted());
        mEnMgr.reset();
        // 5. tear down mobile, then switch SIM
        // 5. tear down mobile, then switch SIM
        mEnMgr.notifyUpstream(false);
        mEnMgr.notifyUpstream(false);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        mEnMgr.reevaluateSimCardProvisioning();
        mEnMgr.reevaluateSimCardProvisioning();
        assertTrue(mEnMgr.uiProvisionCount == 2);
        assertEquals(0, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.silentProvisionCount == 1);
        assertEquals(0, mEnMgr.silentProvisionCount);
        mEnMgr.reset();
        // 6. switch upstream back to mobile again
        // 6. switch upstream back to mobile again
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.notifyUpstream(true);
        mEnMgr.notifyUpstream(true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
        assertTrue(mEnMgr.uiProvisionCount == 2);
        assertEquals(0, mEnMgr.uiProvisionCount);
        assertTrue(mEnMgr.silentProvisionCount == 4);
        assertEquals(3, mEnMgr.silentProvisionCount);
        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
        mEnMgr.reset();
        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
    }
    }


    @Test
    public void testCallStopTetheringWhenUiProvisioningFail() {
        setupForRequiredProvisioning();
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                INVALID_SUBSCRIPTION_ID));
        verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
        mEnMgr.notifyUpstream(true);
        mLooper.dispatchAll();
        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
        mLooper.dispatchAll();
        assertEquals(1, mEnMgr.uiProvisionCount);
        verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
    }


    public class TestStateMachine extends StateMachine {
    public class TestStateMachine extends StateMachine {
        public final ArrayList<Message> messages = new ArrayList<>();
        public final ArrayList<Message> messages = new ArrayList<>();
        private final State
        private final State