blob: 893f3d184acb7097af9cf2c9d00c30b87d0f2913 [file] [log] [blame]
/*
* 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.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.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 KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private DozeParameters mDozeParameters;
private TestableKeyguardSliceProvider mProvider;
private boolean mIsZenMode;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mIsZenMode = false;
mProvider = new TestableKeyguardSliceProvider();
mProvider.attachInfo(getContext(), null);
mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController,
mKeyguardBypassController, mDozeParameters);
SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
}
@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.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.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
public KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
return mKeyguardUpdateMonitor;
}
@Override
protected String getFormattedDateLocked() {
return super.getFormattedDateLocked() + mCounter++;
}
}
}