Revert "Unbind CS if connection is not created within 15 seconds."

This reverts commit 59052739d8583fde2c77d9a1829cc5e7beefa0d9.

Reason for revert: Causes NPE (b/293458004); will submit a clean fix after revert

Merged-In: Ib845c6d52c5839b12cb9f8fa8b72cd0c7b10dbe5

Merged-In: I32fe284a867f1fbd3aa3064023723186a2ba529f

Merged-In: I0ee92a22dd6b3d505899c896b9cb5ec2fbd521f6

Change-Id: Ic020da295236d857df1adcf4f8a5c99d50b8fc42
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index c0951ac..0218124 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -353,17 +353,6 @@
     /** The state of the call. */
     private int mState;
 
-    /**
-     * Determines whether the {@link ConnectionService} has responded to the initial request to
-     * create the connection.
-     *
-     * {@code false} indicates the {@link Call} has been added to Telecom, but the
-     * {@link Connection} has not yet been returned by the associated {@link ConnectionService}.
-     * {@code true} indicates the {@link Call} has an associated {@link Connection} reported by the
-     * {@link ConnectionService}.
-     */
-    private boolean mIsCreateConnectionComplete = false;
-
     /** The handle with which to establish this call. */
     private Uri mHandle;
 
@@ -1049,19 +1038,6 @@
         return mConnectionService;
     }
 
-    /**
-     * @return {@code true} if the connection has been created by the underlying
-     * {@link ConnectionService}, {@code false} otherwise.
-     */
-    public boolean isCreateConnectionComplete() {
-        return mIsCreateConnectionComplete;
-    }
-
-    @VisibleForTesting
-    public void setIsCreateConnectionComplete(boolean isCreateConnectionComplete) {
-        mIsCreateConnectionComplete = isCreateConnectionComplete;
-    }
-
     @VisibleForTesting
     public int getState() {
         return mState;
@@ -2213,7 +2189,6 @@
             CallIdMapper idMapper,
             ParcelableConference conference) {
         Log.v(this, "handleCreateConferenceSuccessful %s", conference);
-        mIsCreateConnectionComplete = true;
         setTargetPhoneAccount(conference.getPhoneAccount());
         setHandle(conference.getHandle(), conference.getHandlePresentation());
 
@@ -2247,7 +2222,6 @@
             CallIdMapper idMapper,
             ParcelableConnection connection) {
         Log.v(this, "handleCreateConnectionSuccessful %s", connection);
-        mIsCreateConnectionComplete = true;
         setTargetPhoneAccount(connection.getPhoneAccount());
         setHandle(connection.getHandle(), connection.getHandlePresentation());
         setCallerDisplayName(
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 7802e08..83a448f 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -39,7 +39,6 @@
 import android.telecom.DisconnectCause;
 import android.telecom.GatewayInfo;
 import android.telecom.Log;
-import android.telecom.Logging.Runnable;
 import android.telecom.Logging.Session;
 import android.telecom.ParcelableConference;
 import android.telecom.ParcelableConnection;
@@ -62,11 +61,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
@@ -80,11 +74,6 @@
 
     private static final String TELECOM_ABBREVIATION = "cast";
 
-    private static final long SERVICE_BINDING_TIMEOUT = 15000L;
-    private ScheduledExecutorService mScheduledExecutor =
-            Executors.newSingleThreadScheduledExecutor();
-    // Pre-allocate space for 2 calls; realistically thats all we should ever need (tm)
-    private final Map<Call, ScheduledFuture<?>> mScheduledFutureMap = new ConcurrentHashMap<>(2);
     private final class Adapter extends IConnectionServiceAdapter.Stub {
 
         @Override
@@ -97,12 +86,6 @@
             try {
                 synchronized (mLock) {
                     logIncoming("handleCreateConnectionComplete %s", callId);
-                    Call call = mCallIdMapper.getCall(callId);
-                    if (mScheduledFutureMap.containsKey(call)) {
-                        ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
-                        existingTimeout.cancel(false /* cancelIfRunning */);
-                        mScheduledFutureMap.remove(call);
-                    }
                     // Check status hints image for cross user access
                     if (connection.getStatusHints() != null) {
                         Icon icon = connection.getStatusHints().getIcon();
@@ -147,12 +130,6 @@
                         conference.getStatusHints().setIcon(StatusHints.
                                 validateAccountIconUserBoundary(icon, callingUserHandle));
                     }
-                    Call call = mCallIdMapper.getCall(callId);
-                    if (mScheduledFutureMap.containsKey(call)) {
-                        ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
-                        existingTimeout.cancel(false /* cancelIfRunning */);
-                        mScheduledFutureMap.remove(call);
-                    }
                     ConnectionServiceWrapper.this
                             .handleCreateConferenceComplete(callId, request, conference);
 
@@ -1255,8 +1232,7 @@
      * @param context The context.
      * @param userHandle The {@link UserHandle} to use when binding.
      */
-    @VisibleForTesting
-    public ConnectionServiceWrapper(
+    ConnectionServiceWrapper(
             ComponentName componentName,
             ConnectionServiceRepository connectionServiceRepository,
             PhoneAccountRegistrar phoneAccountRegistrar,
@@ -1335,26 +1311,6 @@
                         .setIsAdhocConferenceCall(call.isAdhocConferenceCall())
                         .build();
 
-                Runnable r = new Runnable("CSW.cC", mLock) {
-                            @Override
-                            public void loggedRun() {
-                                if (!call.isCreateConnectionComplete()) {
-                                    Log.e(this, new Exception(),
-                                            "Conference %s creation timeout",
-                                            getComponentName());
-                                    Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_TIMEOUT,
-                                            Log.piiHandle(call.getHandle()) + " via:" +
-                                                    getComponentName().getPackageName());
-                                    response.handleCreateConferenceFailure(
-                                            new DisconnectCause(DisconnectCause.ERROR));
-                                }
-                            }
-                        };
-                // Post cleanup to the executor service and cache the future, so we can cancel it if
-                // needed.
-                ScheduledFuture<?> future = mScheduledExecutor.schedule(r.getRunnableToCancel(),
-                        SERVICE_BINDING_TIMEOUT, TimeUnit.MILLISECONDS);
-                mScheduledFutureMap.put(call, future);
                 try {
                     mServiceInterface.createConference(
                             call.getConnectionManagerPhoneAccount(),
@@ -1452,26 +1408,6 @@
                         .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
                         .build();
 
-                Runnable r = new Runnable("CSW.cC", mLock) {
-                            @Override
-                            public void loggedRun() {
-                                if (!call.isCreateConnectionComplete()) {
-                                    Log.e(this, new Exception(),
-                                            "Connection %s creation timeout",
-                                            getComponentName());
-                                    Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_TIMEOUT,
-                                            Log.piiHandle(call.getHandle()) + " via:" +
-                                                    getComponentName().getPackageName());
-                                    response.handleCreateConnectionFailure(
-                                            new DisconnectCause(DisconnectCause.ERROR));
-                                }
-                            }
-                        };
-                // Post cleanup to the executor service and cache the future, so we can cancel it if
-                // needed.
-                ScheduledFuture<?> future = mScheduledExecutor.schedule(r.getRunnableToCancel(),
-                        SERVICE_BINDING_TIMEOUT, TimeUnit.MILLISECONDS);
-                mScheduledFutureMap.put(call, future);
                 try {
                     mServiceInterface.createConnection(
                             call.getConnectionManagerPhoneAccount(),
@@ -1881,8 +1817,7 @@
         }
     }
 
-    @VisibleForTesting
-    public void addCall(Call call) {
+    void addCall(Call call) {
         if (mCallIdMapper.getCallId(call) == null) {
             mCallIdMapper.addCall(call);
         }
@@ -2349,9 +2284,4 @@
         sb.append("]");
         return sb.toString();
     }
-
-    @VisibleForTesting
-    public void setScheduledExecutorService(ScheduledExecutorService service) {
-        mScheduledExecutor = service;
-    }
 }
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index ae7d1a8..f53f239 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -126,10 +126,8 @@
         public static final String STOP_CALL_WAITING_TONE = "STOP_CALL_WAITING_TONE";
         public static final String START_CONNECTION = "START_CONNECTION";
         public static final String CREATE_CONNECTION_FAILED = "CREATE_CONNECTION_FAILED";
-        public static final String CREATE_CONNECTION_TIMEOUT = "CREATE_CONNECTION_TIMEOUT";
         public static final String START_CONFERENCE = "START_CONFERENCE";
         public static final String CREATE_CONFERENCE_FAILED = "CREATE_CONFERENCE_FAILED";
-        public static final String CREATE_CONFERENCE_TIMEOUT = "CREATE_CONFERENCE_TIMEOUT";
         public static final String BIND_CS = "BIND_CS";
         public static final String CS_BOUND = "CS_BOUND";
         public static final String CONFERENCE_WITH = "CONF_WITH";
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 27ed7fd..85d9627 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -978,7 +978,6 @@
         call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle());
         assert(call.isVideoCallingSupportedByPhoneAccount());
         assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
-        call.setIsCreateConnectionComplete(true);
     }
 
     /**
@@ -1002,7 +1001,6 @@
         call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle());
         assert(!call.isVideoCallingSupportedByPhoneAccount());
         assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
-        call.setIsCreateConnectionComplete(true);
     }
 
     /**
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 53d92ce..69ceac3 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -42,7 +42,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static java.lang.Thread.sleep;
 
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -51,7 +50,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Process;
 import android.os.SystemClock;
@@ -73,7 +71,6 @@
 import android.util.Pair;
 import android.widget.Toast;
 
-import com.android.internal.telecom.IConnectionService;
 import com.android.server.telecom.AsyncRingtonePlayer;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallAudioManager;
@@ -88,7 +85,6 @@
 import com.android.server.telecom.ConnectionServiceFocusManager;
 import com.android.server.telecom.ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory;
 import com.android.server.telecom.ConnectionServiceWrapper;
-import com.android.server.telecom.CreateConnectionResponse;
 import com.android.server.telecom.DefaultDialerCache;
 import com.android.server.telecom.EmergencyCallHelper;
 import com.android.server.telecom.HeadsetMediaButton;
@@ -220,7 +216,6 @@
     @Mock private RoleManagerAdapter mRoleManagerAdapter;
     @Mock private ToastFactory mToastFactory;
     @Mock private Toast mToast;
-    @Mock private IConnectionService mIConnectionService;
 
     private CallsManager mCallsManager;
 
@@ -288,19 +283,11 @@
                 eq(SIM_2_HANDLE), any())).thenReturn(SIM_2_ACCOUNT);
         when(mToastFactory.makeText(any(), anyInt(), anyInt())).thenReturn(mToast);
         when(mToastFactory.makeText(any(), any(), anyInt())).thenReturn(mToast);
-        when(mIConnectionService.asBinder()).thenReturn(mock(IBinder.class));
-
-        mComponentContextFixture.addConnectionService(new ComponentName(mContext.getPackageName(),
-                mContext.getPackageName().getClass().getName()), mIConnectionService);
     }
 
     @Override
     @After
     public void tearDown() throws Exception {
-        mComponentContextFixture.removeConnectionService(
-                new ComponentName(mContext.getPackageName(),
-                        mContext.getPackageName().getClass().getName()),
-                mock(IConnectionService.class));
         super.tearDown();
     }
 
@@ -1662,32 +1649,6 @@
         assertTrue(argumentCaptor.getValue().contains("Unavailable phoneAccountHandle"));
     }
 
-    @Test
-    public void testConnectionServiceCreateConnectionTimeout() throws Exception {
-        ConnectionServiceWrapper service = new ConnectionServiceWrapper(new ComponentName(
-                mContext.getPackageName(), mContext.getPackageName().getClass().getName()), null,
-                mPhoneAccountRegistrar, mCallsManager, mContext, mLock, null);
-        TestScheduledExecutorService scheduledExecutorService = new TestScheduledExecutorService();
-        service.setScheduledExecutorService(scheduledExecutorService);
-        Call call = addSpyCall();
-        service.addCall(call);
-        when(call.isCreateConnectionComplete()).thenReturn(false);
-        CreateConnectionResponse response = mock(CreateConnectionResponse.class);
-
-        service.createConnection(call, response);
-        waitUntilConditionIsTrueOrTimeout(new Condition() {
-            @Override
-            public Object expected() {
-                return true;
-            }
-
-            @Override
-            public Object actual() {
-                return scheduledExecutorService.isRunnableScheduledAtTime(15000L);
-            }
-        }, 5000L, "Expected job failed to schedule");
-    }
-
     private Call addSpyCall() {
         return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
     }
@@ -1780,19 +1741,4 @@
         when(mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser()).thenReturn(
                 new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
     }
-
-    private void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
-            String description) throws InterruptedException {
-        final long start = System.currentTimeMillis();
-        while (!condition.expected().equals(condition.actual())
-                && System.currentTimeMillis() - start < timeout) {
-            sleep(50);
-        }
-        assertEquals(description, condition.expected(), condition.actual());
-    }
-
-    protected interface Condition {
-        Object expected();
-        Object actual();
-    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 91ce575..ebb336e 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -650,14 +650,6 @@
         mServiceInfoByComponentName.put(componentName, serviceInfo);
     }
 
-    public void removeConnectionService(
-            ComponentName componentName,
-            IConnectionService service)
-            throws Exception {
-        removeService(ConnectionService.SERVICE_INTERFACE, componentName, service);
-        mServiceInfoByComponentName.remove(componentName);
-    }
-
     public void addInCallService(
             ComponentName componentName,
             IInCallService service,
@@ -735,12 +727,6 @@
         mComponentNameByService.put(service, name);
     }
 
-    private void removeService(String action, ComponentName name, IInterface service) {
-        mComponentNamesByAction.remove(action, name);
-        mServiceByComponentName.remove(name);
-        mComponentNameByService.remove(service);
-    }
-
     private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
         List<ResolveInfo> result = new ArrayList<>();
         for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
diff --git a/tests/src/com/android/server/telecom/tests/TestScheduledExecutorService.java b/tests/src/com/android/server/telecom/tests/TestScheduledExecutorService.java
deleted file mode 100644
index 8ddf42b..0000000
--- a/tests/src/com/android/server/telecom/tests/TestScheduledExecutorService.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.telecom.tests;
-
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Delayed;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A test implementation of a scheduled executor service.
- */
-public class TestScheduledExecutorService implements ScheduledExecutorService {
-    private static final String TAG = "TestScheduledExecutorService";
-
-    private class CompletedFuture<T> implements Future<T>, ScheduledFuture<T> {
-
-        private final Callable<T> mTask;
-        private final long mDelayMs;
-        private Runnable mRunnable;
-
-        CompletedFuture(Callable<T> task) {
-            mTask = task;
-            mDelayMs = 0;
-        }
-
-        @SuppressWarnings("unused")
-        CompletedFuture(Callable<T> task, long delayMs) {
-            mTask = task;
-            mDelayMs = delayMs;
-        }
-
-        CompletedFuture(Runnable task, long delayMs) {
-            mRunnable = task;
-            mTask = (Callable<T>) Executors.callable(task);
-            mDelayMs = delayMs;
-        }
-
-        @Override
-        public boolean cancel(boolean mayInterruptIfRunning) {
-            cancelRunnable(mRunnable);
-            return true;
-        }
-
-        @Override
-        public boolean isCancelled() {
-            return false;
-        }
-
-        @Override
-        public boolean isDone() {
-            return true;
-        }
-
-        @Override
-        public T get() throws InterruptedException, ExecutionException {
-            try {
-                return mTask.call();
-            } catch (Exception e) {
-                throw new ExecutionException(e);
-            }
-        }
-
-        @Override
-        public T get(long timeout, TimeUnit unit)
-                throws InterruptedException, ExecutionException, TimeoutException {
-            try {
-                return mTask.call();
-            } catch (Exception e) {
-                throw new ExecutionException(e);
-            }
-        }
-
-        @Override
-        public long getDelay(TimeUnit unit) {
-            if (unit == TimeUnit.MILLISECONDS) {
-                return mDelayMs;
-            } else {
-                // not implemented
-                return 0;
-            }
-        }
-
-        @Override
-        public int compareTo(Delayed o) {
-            if (o == null) return 1;
-            if (o.getDelay(TimeUnit.MILLISECONDS) > mDelayMs) return -1;
-            if (o.getDelay(TimeUnit.MILLISECONDS) < mDelayMs) return 1;
-            return 0;
-        }
-    }
-
-    private long mClock = 0;
-    private Map<Long, Runnable> mScheduledRunnables = new HashMap<>();
-    private Map<Runnable, Long> mRepeatDuration = new HashMap<>();
-
-    @Override
-    public void shutdown() {
-    }
-
-    @Override
-    public List<Runnable> shutdownNow() {
-        return null;
-    }
-
-    @Override
-    public boolean isShutdown() {
-        return false;
-    }
-
-    @Override
-    public boolean isTerminated() {
-        return false;
-    }
-
-    @Override
-    public boolean awaitTermination(long timeout, TimeUnit unit) {
-        return false;
-    }
-
-    @Override
-    public <T> Future<T> submit(Callable<T> task) {
-        return new TestScheduledExecutorService.CompletedFuture<>(task);
-    }
-
-    @Override
-    public <T> Future<T> submit(Runnable task, T result) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public Future<?> submit(Runnable task) {
-        task.run();
-        return new TestScheduledExecutorService.CompletedFuture<>(() -> null);
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
-                                         TimeUnit unit) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
-        // Schedule the runnable for execution at the specified time.
-        long scheduledTime = getNextExecutionTime(delay, unit);
-        mScheduledRunnables.put(scheduledTime, command);
-
-        Log.i(TAG, "schedule: runnable=" + System.identityHashCode(command) + ", time="
-                + scheduledTime);
-
-        return new TestScheduledExecutorService.CompletedFuture<Runnable>(command, delay);
-    }
-
-    @Override
-    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    @Override
-    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
-                                                  TimeUnit unit) {
-        return scheduleWithFixedDelay(command, initialDelay, period, unit);
-    }
-
-    @Override
-    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
-                                                     long delay, TimeUnit unit) {
-        // Schedule the runnable for execution at the specified time.
-        long nextScheduledTime = getNextExecutionTime(delay, unit);
-        mScheduledRunnables.put(nextScheduledTime, command);
-        mRepeatDuration.put(command, unit.toMillis(delay));
-
-        return new TestScheduledExecutorService.CompletedFuture<Runnable>(command, delay);
-    }
-
-    private long getNextExecutionTime(long delay, TimeUnit unit) {
-        long delayMillis = unit.toMillis(delay);
-        return mClock + delayMillis;
-    }
-
-    @Override
-    public void execute(Runnable command) {
-        command.run();
-    }
-
-    /**
-     * Used in unit tests, used to add a delta to the "clock" so that we can fire off scheduled
-     * items and reschedule the repeats.
-     * @param duration The duration (millis) to add to the clock.
-     */
-    public void advanceTime(long duration) {
-        Map<Long, Runnable> nextRepeats = new HashMap<>();
-        List<Runnable> toRun = new ArrayList<>();
-        mClock += duration;
-        Iterator<Map.Entry<Long, Runnable>> iterator = mScheduledRunnables.entrySet().iterator();
-        while (iterator.hasNext()) {
-            Map.Entry<Long, Runnable> entry = iterator.next();
-            if (mClock >= entry.getKey()) {
-                toRun.add(entry.getValue());
-
-                Runnable r = entry.getValue();
-                Log.i(TAG, "advanceTime: runningRunnable=" + System.identityHashCode(r));
-                // If this is a repeating scheduled item, schedule the repeat.
-                if (mRepeatDuration.containsKey(r)) {
-                    // schedule next execution
-                    nextRepeats.put(mClock + mRepeatDuration.get(r), entry.getValue());
-                }
-                iterator.remove();
-            }
-        }
-
-        // Update things at the end to avoid concurrent access.
-        mScheduledRunnables.putAll(nextRepeats);
-        toRun.forEach(r -> r.run());
-    }
-
-    /**
-     * Used from a {@link CompletedFuture} as defined above to cancel a scheduled task.
-     * @param r The runnable to cancel.
-     */
-    private void cancelRunnable(Runnable r) {
-        Optional<Map.Entry<Long, Runnable>> found = mScheduledRunnables.entrySet().stream()
-                .filter(e -> e.getValue() == r)
-                .findFirst();
-        if (found.isPresent()) {
-            mScheduledRunnables.remove(found.get().getKey());
-        }
-        mRepeatDuration.remove(r);
-        Log.i(TAG, "cancelRunnable: runnable=" + System.identityHashCode(r));
-    }
-
-    public int getNumberOfScheduledRunnables() {
-        return mScheduledRunnables.size();
-    }
-
-    public boolean isRunnableScheduledAtTime(long time) {
-        return mScheduledRunnables.containsKey(time);
-    }
-}
\ No newline at end of file