| /* |
| * Copyright (C) 2017 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.systemui.keyguard; |
| |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.reset; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.app.AlarmManager; |
| import android.content.ContentResolver; |
| import android.media.MediaMetadata; |
| import android.media.session.PlaybackState; |
| import android.net.Uri; |
| import android.provider.Settings; |
| import android.testing.AndroidTestingRunner; |
| import android.testing.TestableLooper; |
| import android.testing.TestableLooper.RunWithLooper; |
| |
| import androidx.slice.Slice; |
| import androidx.slice.SliceItem; |
| import androidx.slice.SliceProvider; |
| import androidx.slice.SliceSpecs; |
| import androidx.slice.builders.ListBuilder; |
| import androidx.slice.core.SliceQuery; |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.keyguard.KeyguardUpdateMonitor; |
| import com.android.systemui.SysuiTestCase; |
| import com.android.systemui.plugins.statusbar.StatusBarStateController; |
| import com.android.systemui.statusbar.NotificationMediaManager; |
| import com.android.systemui.statusbar.StatusBarState; |
| import com.android.systemui.statusbar.phone.DozeParameters; |
| import com.android.systemui.statusbar.phone.KeyguardBypassController; |
| import com.android.systemui.statusbar.policy.ZenModeController; |
| import com.android.systemui.util.wakelock.SettableWakeLock; |
| |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.concurrent.TimeUnit; |
| |
| @SmallTest |
| @RunWith(AndroidTestingRunner.class) |
| @RunWithLooper |
| public class KeyguardSliceProviderTest extends SysuiTestCase { |
| |
| @Mock |
| private ContentResolver mContentResolver; |
| @Mock |
| private AlarmManager mAlarmManager; |
| @Mock |
| private NotificationMediaManager mNotificationMediaManager; |
| @Mock |
| private StatusBarStateController mStatusBarStateController; |
| @Mock |
| private KeyguardBypassController mKeyguardBypassController; |
| @Mock |
| private ZenModeController mZenModeController; |
| @Mock |
| private SettableWakeLock mMediaWakeLock; |
| @Mock |
| private DozeParameters mDozeParameters; |
| private KeyguardUpdateMonitor mKeyguardUpdateMonitor; |
| private TestableKeyguardSliceProvider mProvider; |
| private boolean mIsZenMode; |
| |
| @Before |
| public void setup() { |
| MockitoAnnotations.initMocks(this); |
| mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class); |
| mIsZenMode = false; |
| mProvider = new TestableKeyguardSliceProvider(); |
| mProvider.attachInfo(getContext(), null); |
| mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController, |
| mKeyguardBypassController, mDozeParameters); |
| SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST))); |
| } |
| |
| @After |
| public void tearDown() { |
| mProvider.onDestroy(); |
| } |
| |
| @Test |
| public void registersClockUpdate() { |
| Assert.assertTrue("registerClockUpdate should have been called during initialization.", |
| mProvider.isRegistered()); |
| } |
| |
| @Test |
| public void returnsValidSlice() { |
| Slice slice = mProvider.onBindSlice(mProvider.getUri()); |
| SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT, |
| android.app.slice.Slice.HINT_TITLE, |
| null /* nonHints */); |
| Assert.assertNotNull("Slice must provide a title.", text); |
| } |
| |
| @Test |
| public void onBindSlice_readsMedia_withoutBypass() { |
| MediaMetadata metadata = mock(MediaMetadata.class); |
| when(metadata.getText(any())).thenReturn("metadata"); |
| mProvider.onDozingChanged(true); |
| mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING); |
| mProvider.onBindSlice(mProvider.getUri()); |
| verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE)); |
| verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_ARTIST)); |
| verify(mNotificationMediaManager).getMediaIcon(); |
| } |
| |
| @Test |
| public void onBindSlice_readsMedia_withBypass_notDozing() { |
| MediaMetadata metadata = mock(MediaMetadata.class); |
| when(metadata.getText(any())).thenReturn("metadata"); |
| when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); |
| when(mDozeParameters.getAlwaysOn()).thenReturn(true); |
| mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING); |
| mProvider.onBindSlice(mProvider.getUri()); |
| verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE)); |
| verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_ARTIST)); |
| verify(mNotificationMediaManager).getMediaIcon(); |
| } |
| |
| @Test |
| public void cleansDateFormat() { |
| mProvider.mKeyguardUpdateMonitorCallback.onTimeZoneChanged(null); |
| TestableLooper.get(this).processAllMessages(); |
| Assert.assertEquals("Date format should have been cleaned.", 1 /* expected */, |
| mProvider.mCleanDateFormatInvokations); |
| } |
| |
| @Test |
| public void updatesClock() { |
| mProvider.mKeyguardUpdateMonitorCallback.onTimeChanged(); |
| TestableLooper.get(this).processAllMessages(); |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| } |
| |
| @Test |
| public void schedulesAlarm12hBefore() { |
| long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(16); |
| AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null); |
| mProvider.onNextAlarmChanged(alarmClockInfo); |
| |
| long twelveHours = TimeUnit.HOURS.toMillis(KeyguardSliceProvider.ALARM_VISIBILITY_HOURS); |
| long triggerAt = in16Hours - twelveHours; |
| verify(mAlarmManager).setExact(eq(AlarmManager.RTC), eq(triggerAt), anyString(), any(), |
| any()); |
| } |
| |
| @Test |
| public void updatingNextAlarmInvalidatesSlice() { |
| long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(8); |
| AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null); |
| mProvider.onNextAlarmChanged(alarmClockInfo); |
| |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| } |
| |
| @Test |
| public void onZenChanged_updatesSlice() { |
| mProvider.onZenChanged(Settings.Global.ZEN_MODE_ALARMS); |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| } |
| |
| @Test |
| public void addZenMode_addedToSlice() { |
| ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri(), |
| ListBuilder.INFINITY)); |
| mProvider.addZenModeLocked(listBuilder); |
| verify(listBuilder, never()).addRow(any(ListBuilder.RowBuilder.class)); |
| |
| mIsZenMode = true; |
| mProvider.addZenModeLocked(listBuilder); |
| verify(listBuilder).addRow(any(ListBuilder.RowBuilder.class)); |
| } |
| |
| @Test |
| public void onMetadataChanged_updatesSlice() { |
| mProvider.onStateChanged(StatusBarState.KEYGUARD); |
| mProvider.onDozingChanged(true); |
| reset(mContentResolver); |
| mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING); |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| |
| // Hides after waking up |
| reset(mContentResolver); |
| mProvider.onDozingChanged(false); |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| } |
| |
| @Test |
| public void onDozingChanged_updatesSliceIfMedia() { |
| mProvider.onStateChanged(StatusBarState.KEYGUARD); |
| mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING); |
| reset(mContentResolver); |
| // Show media when dozing |
| mProvider.onDozingChanged(true); |
| verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); |
| |
| // Do not notify again if nothing changed |
| reset(mContentResolver); |
| mProvider.onDozingChanged(true); |
| verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null)); |
| } |
| |
| @Test |
| public void onDestroy_noCrash() { |
| mProvider.onDestroy(); |
| } |
| |
| @Test |
| public void onDestroy_unregisterListeners() { |
| mProvider.registerClockUpdate(); |
| mProvider.onDestroy(); |
| verify(mMediaWakeLock).setAcquired(eq(false)); |
| verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class)); |
| verify(mKeyguardUpdateMonitor).removeCallback(any()); |
| } |
| |
| private class TestableKeyguardSliceProvider extends KeyguardSliceProvider { |
| int mCleanDateFormatInvokations; |
| private int mCounter; |
| |
| Uri getUri() { |
| return mSliceUri; |
| } |
| |
| @Override |
| public boolean onCreateSliceProvider() { |
| super.onCreateSliceProvider(); |
| mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager; |
| mContentResolver = KeyguardSliceProviderTest.this.mContentResolver; |
| mZenModeController = KeyguardSliceProviderTest.this.mZenModeController; |
| mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock; |
| return true; |
| } |
| |
| @Override |
| protected boolean isDndOn() { |
| return mIsZenMode; |
| } |
| |
| @Override |
| void cleanDateFormatLocked() { |
| super.cleanDateFormatLocked(); |
| mCleanDateFormatInvokations++; |
| } |
| |
| @Override |
| protected String getFormattedDateLocked() { |
| return super.getFormattedDateLocked() + mCounter++; |
| } |
| } |
| |
| } |