Merge "Sending a TIME_TICK on screen_on"
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 08034f7..0fa996e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1123,8 +1123,6 @@
         rescheduleKernelAlarmsLocked();
         updateNextAlarmClockLocked();
 
-        // And send a TIME_TICK right now, since it is important to get the UI updated.
-        mHandler.post(() ->  getContext().sendBroadcastAsUser(mTimeTickIntent, UserHandle.ALL));
     }
 
     static final class InFlight {
@@ -1298,7 +1296,7 @@
         mInjector.init();
 
         synchronized (mLock) {
-            mHandler = new AlarmHandler(Looper.myLooper());
+            mHandler = new AlarmHandler();
             mConstants = new Constants(mHandler);
 
             mNextWakeup = mNextNonWakeup = 0;
@@ -3050,6 +3048,9 @@
                         mNonInteractiveTime = dur;
                     }
                 }
+                // And send a TIME_TICK right now, since it is important to get the UI updated.
+                mHandler.post(() ->
+                        getContext().sendBroadcastAsUser(mTimeTickIntent, UserHandle.ALL));
             } else {
                 mNonInteractiveStartTime = nowELAPSED;
             }
@@ -3838,7 +3839,8 @@
         mWakeLock.setWorkSource(null);
     }
 
-    private class AlarmHandler extends Handler {
+    @VisibleForTesting
+    class AlarmHandler extends Handler {
         public static final int ALARM_EVENT = 1;
         public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
         public static final int LISTENER_TIMEOUT = 3;
@@ -3847,8 +3849,8 @@
         public static final int APP_STANDBY_PAROLE_CHANGED = 6;
         public static final int REMOVE_FOR_STOPPED = 7;
 
-        AlarmHandler(Looper looper) {
-            super(looper);
+        AlarmHandler() {
+            super(Looper.myLooper());
         }
 
         public void postRemoveForStopped(int uid) {
@@ -3961,8 +3963,8 @@
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
             setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
-                    0, null, mTimeTickTrigger, null, AlarmManager.FLAG_STANDALONE, workSource,
-                    null, Process.myUid(), "android");
+                    0, null, mTimeTickTrigger, "TIME_TICK", AlarmManager.FLAG_STANDALONE,
+                    workSource, null, Process.myUid(), "android");
 
             // Finally, remember when we set the tick alarm
             synchronized (mLock) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 3979a8e..148faad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -25,7 +25,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -42,7 +41,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -66,7 +64,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -96,6 +93,8 @@
     @Mock
     private ContentResolver mMockResolver;
     @Mock
+    private Context mMockContext;
+    @Mock
     private IActivityManager mIActivityManager;
     @Mock
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -221,17 +220,16 @@
                 .thenReturn(STANDBY_BUCKET_ACTIVE);
         doReturn(Looper.getMainLooper()).when(Looper::myLooper);
 
-        final Context context = spy(InstrumentationRegistry.getTargetContext());
-        when(context.getContentResolver()).thenReturn(mMockResolver);
-        doNothing().when(mMockResolver).registerContentObserver(any(), anyBoolean(), any());
+        when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
         doReturn("min_futurity=0").when(() ->
                 Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
-        mInjector = new Injector(context);
-        mService = new AlarmManagerService(context, mInjector);
+        mInjector = new Injector(mMockContext);
+        mService = new AlarmManagerService(mMockContext, mInjector);
         spyOn(mService);
         doNothing().when(mService).publishBinderService(any(), any());
         mService.onStart();
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+        spyOn(mService.mHandler);
 
         assertEquals(0, mService.mConstants.MIN_FUTURITY);
         assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
@@ -273,7 +271,7 @@
 
         final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor =
                 ArgumentCaptor.forClass(PendingIntent.OnFinished.class);
-        verify(alarmPi).send(any(Context.class), eq(0), any(Intent.class),
+        verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
                 onFinishedCaptor.capture(), any(Handler.class), isNull(), any());
         verify(mWakeLock).acquire();
         onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null);
@@ -423,11 +421,23 @@
         assertNotNull(restrictedAlarms.get(TEST_CALLING_UID));
 
         listenerArgumentCaptor.getValue().unblockAlarmsForUid(TEST_CALLING_UID);
-        verify(alarmPi).send(any(Context.class), eq(0), any(Intent.class), any(),
+        verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), any(),
                 any(Handler.class), isNull(), any());
         assertNull(restrictedAlarms.get(TEST_CALLING_UID));
     }
 
+    @Test
+    public void sendsTimeTickOnInteractive() {
+        final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        // Stubbing so the handler doesn't actually run the runnable.
+        doReturn(true).when(mService.mHandler).post(runnableCaptor.capture());
+        // change interactive state: false -> true
+        mService.interactiveStateChangedLocked(false);
+        mService.interactiveStateChangedLocked(true);
+        runnableCaptor.getValue().run();
+        verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {