External view test

CYNGNOS-3042

Change-Id: Ibdd11b631c6deea3eb030ffb1ba55b6ca5fe022b
This commit is contained in:
Danesh M 2016-06-08 11:25:08 -07:00 committed by Gerrit Code Review
parent aa11b3330a
commit b6e71bc544
7 changed files with 1035 additions and 2 deletions

View File

@ -20,7 +20,8 @@ LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_JAVA_LIBRARIES := \
org.cyanogenmod.platform.sdk \
android-support-test
android-support-test \
mockito-target
LOCAL_DEX_PREOPT := false
@ -40,7 +41,8 @@ LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_JAVA_LIBRARIES := \
org.cyanogenmod.platform.sdk \
android-support-test
android-support-test \
mockito-target
LOCAL_DEX_PREOPT := false

View File

@ -43,6 +43,12 @@
-dontwarn junit.**
-dontwarn org.junit.**
# keep mockito methods
-keep class org.mockito.** { *; }
-keep interface org.mockito.** { *; }
-keep class com.google.dexmaker.** { *; }
-keep interface com.google.dexmaker.** { *; }
# Always process
-forceprocessing

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2016, The CyanogenMod 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 org.cyanogenmod.tests.common;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteCallbackList;
import org.junit.Assert;
import org.mockito.Mockito;
import java.lang.reflect.Field;
/**
* Helper class to mock stubs for IInterfaces
* Ensures that when querying the local interface
* we return the instance itself as to preserve the mock instance
*/
public final class MockIBinderStubForInterface {
private MockIBinderStubForInterface() {}
private static <T extends IBinder> String getStubDescriptor(Class<T> stubClass) {
String descriptor = null;
try {
Field f = stubClass.getDeclaredField("DESCRIPTOR");
f.setAccessible(true);
descriptor = (String) f.get(stubClass);
} catch (NoSuchFieldException | IllegalAccessException e) {
Assert.fail(e.getMessage());
}
return descriptor;
}
public static <T extends IBinder> T getMockInterface(Class<T> stub) {
String descriptor = getStubDescriptor(stub);
T mockInterface = Mockito.mock(stub);
Mockito.doReturn(mockInterface)
.when(mockInterface)
.queryLocalInterface(descriptor == null ?
Mockito.anyString() : Mockito.eq(descriptor));
Mockito.doReturn(Mockito.mock(IBinder.class))
.when((IInterface) mockInterface)
.asBinder();
return mockInterface;
}
}

View File

@ -0,0 +1,200 @@
package org.cyanogenmod.tests.common;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.test.InstrumentationTestCase;
import android.test.ServiceTestCase;
/**
* Tests a service in its own Thread.
*
*
* <p>
* The {@link ServiceTestCase} class creates the service in the same thread the
* test is running. In consequence Handlers and other constructs that depend on
* the fact that the service methods are always run on the <em>main thread</em>
* won't work.
* </p>
*
* <p>
* To circumvent this, this test class creates a {@link HandlerThread} on setup
* to simulate the main tread and provides helper constructs to ease the
* communication between the Service and the test class :
* </p>
*
* <ul>
* <li>The {@link #runOnServiceThread(Runnable)} methods allows to run code on
* the service pseudo-main thread.</li>
* <li>The {@link #startService(boolean, ServiceRunnable)} mehod allows starting
* the service in its own thread with some additional initialization code.</li>
* </ul>
*
*
* @author Antoine Martin
*
*/
public abstract class ThreadServiceTestCase<T extends Service> extends ServiceTestCase<T> {
/** Typical maximum wait time for something to happen on the service */
public static final long WAIT_TIME = 5 * 1000;
/*
* This class provides final mutable values through indirection
*/
static class Holder<H> {
H value;
}
protected Handler serviceHandler;
protected Looper serviceLooper;
/*
* Got to catch this again because of damn package visibility of
* mServiceClass in base class.
*/
protected Class<T> serviceClass;
public ThreadServiceTestCase(Class<T> serviceClass) {
super(serviceClass);
this.serviceClass = serviceClass;
}
@Override
protected void setUp() throws Exception {
super.setUp();
// Setup service thread
HandlerThread serviceThread = new HandlerThread("[" + serviceClass.getSimpleName() + "Thread]");
serviceThread.start();
serviceLooper = serviceThread.getLooper();
serviceHandler = new Handler(serviceLooper);
}
@Override
public void testServiceTestCaseSetUpProperly() throws Exception {
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
// teardown service thread
if (serviceLooper != null)
serviceLooper.quit();
serviceHandler = null;
}
/**
* Runs the specified runnable on the service tread and waits for its
* completion.
*
* @see InstrumentationTestCase#runTestOnUiThread(Runnable)
* @param r
* The runnable to run on the pseudo-main thread.
*/
protected void runOnServiceThread(final Runnable r) {
final CountDownLatch serviceSignal = new CountDownLatch(1);
serviceHandler.post(new Runnable() {
@Override
public void run() {
r.run();
serviceSignal.countDown();
}
});
try {
serviceSignal.await();
} catch (InterruptedException ie) {
fail("The Service thread has been interrupted");
}
}
/**
* Runnable interface allowing service initialization personalization.
*
* @author Antoine Martin
*
*/
protected interface ServiceRunnable {
public void run(Service service);
}
/**
* Initialize the service in its own thread and returns it.
*
* @param bound
* if {@code true}, the service will be created as if it was
* bound by a client. if {@code false}, it will be created by a
* {@code startService} call.
* @param r
* {@link ServiceRunnable} instance that will be called with the
* created service.
* @return The created service.
*/
protected T startService(final ServiceRunnable r) {
final Holder<T> serviceHolder = new Holder<T>();
// I want to create my service in its own 'Main thread'
// So it can use its handler
runOnServiceThread(new Runnable() {
@Override
public void run() {
T service = null;
startService(new Intent(getContext(), serviceClass));
service = getService();
if (r != null)
r.run(service);
serviceHolder.value = service;
}
});
return serviceHolder.value;
}
protected IBinder bindService(final ServiceRunnable r) {
final Holder<IBinder> serviceHolder = new Holder<IBinder>();
// I want to create my service in its own 'Main thread'
// So it can use its handler
runOnServiceThread(new Runnable() {
@Override
public void run() {
T service = null;
IBinder binder = bindService(new Intent(getContext(), serviceClass));
service = getService();
if (r != null)
r.run(service);
serviceHolder.value = binder;
}
});
return serviceHolder.value;
}
public static class ServiceSyncHelper {
// The semaphore will wakeup clients
protected final Semaphore semaphore = new Semaphore(0);
/**
* Waits for some response coming from the service.
*
* @param timeout
* The maximum time to wait.
* @throws InterruptedException
* if the Thread is interrupted or reaches the timeout.
*/
public synchronized void waitListener(long timeout) throws InterruptedException {
if (!semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS))
throw new InterruptedException();
}
}
}

View File

@ -0,0 +1,132 @@
/**
* Copyright (c) 2016, The CyanogenMod 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 org.cyanogenmod.tests.externalviews.keyguardexternalviews;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Space;
import cyanogenmod.externalviews.KeyguardExternalViewProviderService;
import org.mockito.Mockito;
public class ViewProviderService extends KeyguardExternalViewProviderService {
private ViewProvider mProvider;
public ViewProviderService() {}
@Override
public KeyguardExternalViewProviderService.Provider createExternalView(Bundle options) {
if (mProvider == null) {
mProvider = Mockito.spy(new ViewProvider(options));
}
return mProvider;
}
public ViewProvider getProvider() {
return mProvider;
}
public class ViewProvider extends KeyguardExternalViewProviderService.Provider {
private ViewProvider mTracker;
private View mView;
public ViewProvider(Bundle options) {
super(options);
}
public View getView() {
return mView;
}
public ViewProvider getTracker() {
return mTracker;
}
@Override
public View onCreateView() {
if (mTracker == null) {
mTracker = Mockito.mock(ViewProvider.class);
}
mTracker.onCreateView();
if (mView == null) {
mView = new Space(getBaseContext());
}
return mView;
}
@Override
public void onKeyguardShowing(boolean screenOn) {
mTracker.onKeyguardShowing(screenOn);
}
@Override
public void onKeyguardDismissed() {
mTracker.onKeyguardDismissed();
}
@Override
public void onBouncerShowing(boolean showing) {
mTracker.onBouncerShowing(showing);
}
@Override
public void onScreenTurnedOn() {
mTracker.onScreenTurnedOn();
}
@Override
public void onScreenTurnedOff() {
mTracker.onScreenTurnedOff();
}
@Override
protected void onAttach() {
mTracker.onAttach();
}
@Override
protected void onDetach() {
mTracker.onDetach();
}
@Override
protected void onLockscreenSlideOffsetChanged(float swipeProgress) {
mTracker.onLockscreenSlideOffsetChanged(swipeProgress);
}
public boolean requestDismissImpl() {
return requestDismiss();
}
public boolean requestDismissAndStartActivityImpl(Intent intent) {
return requestDismissAndStartActivity(intent);
}
public void setInteractivityImpl(boolean interactive) {
setInteractivity(interactive);
}
public void slideLockscreenInImpl() {
slideLockscreenIn();
}
public Bundle getOptionsImpl() {
return getOptions();
}
public void collapseNotificationPanelImpl() {
mTracker.collapseNotificationPanelImpl();
collapseNotificationPanel();
}
}
};

View File

@ -0,0 +1,380 @@
/**
* Copyright (c) 2015-2016, The CyanogenMod 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 org.cyanogenmod.tests.externalviews.keyguardexternalviews;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.*;
import android.test.ServiceTestCase;
import android.view.*;
import android.widget.Space;
import android.widget.TextView;
import cyanogenmod.externalviews.IExternalViewProviderFactory;
import cyanogenmod.externalviews.IKeyguardExternalViewCallbacks;
import cyanogenmod.externalviews.IKeyguardExternalViewProvider;
import cyanogenmod.externalviews.KeyguardExternalViewProviderService;
import org.cyanogenmod.tests.common.MockIBinderStubForInterface;
import org.cyanogenmod.tests.common.ThreadServiceTestCase;
import org.junit.Assert;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.lang.reflect.Field;
public class KeyguardExternalProviderTest extends ThreadServiceTestCase<ViewProviderService> {
private WindowManager mWindowManagerMock;
private IExternalViewProviderFactory mProvider;
public KeyguardExternalProviderTest() {
super(ViewProviderService.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
IBinder bind = bindService((ServiceRunnable) null);
assert (bind != null);
mProvider = IExternalViewProviderFactory.Stub.asInterface(bind);
assert (mProvider != null);
final Bundle bundle = new Bundle();
IBinder bindView = mProvider.createExternalView(bundle);
IKeyguardExternalViewProvider view = IKeyguardExternalViewProvider.Stub.asInterface(bindView);
assert (view != null);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService(), Mockito.times(1))
.createExternalView(Mockito.eq(bundle));
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onCreateView();
}
});
}
@Override
protected void setupService() {
super.setupService();
// Update the service instance with our spy so we can track it
try {
Field f = ServiceTestCase.class.getDeclaredField("mService");
f.setAccessible(true);
ViewProviderService woot = ViewProviderService.class.newInstance();
ViewProviderService spy = Mockito.spy(woot);
f.set(this, spy);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
// Setup mock context
Context context = Mockito.mock(Context.class, Mockito.CALLS_REAL_METHODS);
Mockito.doReturn(getContext().getApplicationInfo()).when(context).getApplicationInfo();
Mockito.doReturn(getContext().getResources()).when(context).getResources();
Mockito.doReturn(getContext().getTheme()).when(context).getTheme();
Mockito.doReturn(getContext().getPackageManager()).when(context).getPackageManager();
Mockito.doReturn(1).when(context).checkCallingOrSelfPermission(Mockito.anyString());
Mockito.doReturn(getContext().getMainLooper()).when(context).getMainLooper();
// Setup mock window manager
mWindowManagerMock = Mockito.mock(WindowManager.class);
WindowManager actualWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Mockito.doReturn(mWindowManagerMock).when(context).getSystemService(Mockito.eq(Context.WINDOW_SERVICE));
Mockito.doReturn(actualWindowManager.getDefaultDisplay()).when(mWindowManagerMock).getDefaultDisplay();
Mockito.doReturn(getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.when(context).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Attach our mock context to service
getService().attach(
context,
null, // ActivityThread not actually used in Service
ViewProviderService.class.getName(),
null, // token not needed when not talking with the activity manager
getApplication(),
null // mocked services don't talk with the activity manager
);
}
public void testCallbacks() throws Exception {
IBinder bind = getService().onBind(new Intent());
final IExternalViewProviderFactory provider = IExternalViewProviderFactory.Stub.asInterface(bind);
assert (provider != null);
// Ensure on bind we were asked to create an external view
final Bundle bundle = new Bundle();
IBinder bindView = provider.createExternalView(bundle);
final IKeyguardExternalViewProvider view = IKeyguardExternalViewProvider.Stub.asInterface(bindView);
assert (view != null);
// Ensure the bundle we constructed with is intact
Bundle b = getService().getProvider().getOptionsImpl();
assert (b == bundle);
Mockito.reset(getService().getProvider().getTracker());
view.onScreenTurnedOff();
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onScreenTurnedOff();
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onKeyguardDismissed();
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onKeyguardDismissed();
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onBouncerShowing(true);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onBouncerShowing(Mockito.eq(true));
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onKeyguardShowing(true);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onKeyguardShowing(Mockito.eq(true));
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onLockscreenSlideOffsetChanged(1f);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.onLockscreenSlideOffsetChanged(Mockito.eq(1f));
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onAttach(null);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1)).onAttach();
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
ArgumentCaptor<WindowManager.LayoutParams> params = ArgumentCaptor
.forClass(WindowManager.LayoutParams.class);
ArgumentCaptor<ViewGroup> viewGroup = ArgumentCaptor
.forClass(ViewGroup.class);
Mockito.verify(mWindowManagerMock, Mockito.times(1))
.addView(viewGroup.capture(), params.capture());
ViewGroup decorView = viewGroup.getAllValues().get(0);
assert (decorView.getChildCount() == 1);
assert (decorView.getChildAt(0) == getService().getProvider().getView());
WindowManager.LayoutParams param = params.getAllValues().get(0);
assert ((param.type & WindowManager.LayoutParams.TYPE_KEYGUARD_PANEL) != 0);
int flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_FULLSCREEN;
assert ((param.flags & flags) != 0);
assert ((param.gravity & Gravity.LEFT | Gravity.TOP) != 0);
assert ((param.format & PixelFormat.TRANSPARENT) != 0);
}
});
Mockito.reset(getService().getProvider().getTracker());
view.onDetach();
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1)).onDetach();
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
ArgumentCaptor<ViewGroup> viewGroup = ArgumentCaptor
.forClass(ViewGroup.class);
Mockito.verify(mWindowManagerMock, Mockito.times(1))
.removeView(viewGroup.capture());
ViewGroup decorView = viewGroup.getAllValues().get(0);
assert (decorView.getChildCount() == 1);
assert (decorView.getChildAt(0) == getService().getProvider().getView());
}
});
}
public void testCallbackRegistration() throws Exception {
assert (getService() != null);
IBinder bind = getService().onBind(new Intent());
final IExternalViewProviderFactory provider = IExternalViewProviderFactory.Stub.asInterface(bind);
assert (provider != null);
// Ensure on bind we were asked to create an external view
final Bundle bundle = new Bundle();
IBinder bindView = provider.createExternalView(bundle);
final IKeyguardExternalViewProvider view = IKeyguardExternalViewProvider.Stub.asInterface(bindView);
assert (view != null);
final IKeyguardExternalViewCallbacks.Stub callback = MockIBinderStubForInterface
.getMockInterface(IKeyguardExternalViewCallbacks.Stub.class);
view.registerCallback(callback);
getService().getProvider().requestDismissImpl();
runOnServiceThread(new Runnable() {
@Override
public void run() {
try {
Mockito.verify(callback, Mockito.times(1)).requestDismiss();
Mockito.verify(callback, Mockito.times(1)).asBinder();
} catch (RemoteException e) {
Assert.fail(e.getMessage());
}
Mockito.verifyNoMoreInteractions(callback);
}
});
Mockito.reset(callback);
final Intent i = new Intent();
getService().getProvider().requestDismissAndStartActivityImpl(i);
runOnServiceThread(new Runnable() {
@Override
public void run() {
try {
Mockito.verify(callback, Mockito.times(1)).requestDismissAndStartActivity(Mockito.eq(i));
} catch (RemoteException e) {
Assert.fail(e.getMessage());
}
Mockito.verifyNoMoreInteractions(callback);
}
});
Mockito.reset(callback);
getService().getProvider().setInteractivityImpl(true);
runOnServiceThread(new Runnable() {
@Override
public void run() {
try {
Mockito.verify(callback, Mockito.times(1)).setInteractivity(Mockito.eq(true));
} catch (RemoteException e) {
Assert.fail(e.getMessage());
}
Mockito.verifyNoMoreInteractions(callback);
}
});
Mockito.reset(callback);
getService().getProvider().slideLockscreenInImpl();
runOnServiceThread(new Runnable() {
@Override
public void run() {
try {
Mockito.verify(callback, Mockito.times(1)).slideLockscreenIn();
} catch (RemoteException e) {
Assert.fail(e.getMessage());
}
Mockito.verifyNoMoreInteractions(callback);
}
});
Mockito.reset(getService().getProvider().getTracker());
getService().getProvider().collapseNotificationPanelImpl();
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verify(getService().getProvider().getTracker(), Mockito.times(1))
.collapseNotificationPanelImpl();
Mockito.verifyNoMoreInteractions(getService().getProvider().getTracker());
}
});
}
public void testAlterWindow() throws Exception {
assert (getService() != null);
IBinder bind = getService().onBind(new Intent());
final IExternalViewProviderFactory provider = IExternalViewProviderFactory.Stub.asInterface(bind);
assert (provider != null);
// Ensure on bind we were asked to create an external view
final Bundle bundle = new Bundle();
IBinder bindView = provider.createExternalView(bundle);
final IKeyguardExternalViewProvider view = IKeyguardExternalViewProvider.Stub.asInterface(bindView);
assert (view != null);
// Test visible false
Mockito.reset(mWindowManagerMock);
final Rect rect = new Rect(0, 0, 100, 100);
view.alterWindow(0, 0, 100, 100, false, rect);
runOnServiceThread(new Runnable() {
@Override
public void run() {
Mockito.verifyNoMoreInteractions(mWindowManagerMock);
}
});
// Test visible true
Mockito.reset(mWindowManagerMock);
view.alterWindow(10, 20, 30, 40, true, rect);
runOnServiceThread(new Runnable() {
@Override
public void run() {
ArgumentCaptor<WindowManager.LayoutParams> params = ArgumentCaptor
.forClass(WindowManager.LayoutParams.class);
ArgumentCaptor<ViewGroup> viewGroup = ArgumentCaptor
.forClass(ViewGroup.class);
Mockito.verify(mWindowManagerMock, Mockito.times(1))
.updateViewLayout(viewGroup.capture(), params.capture());
ViewGroup decorView = viewGroup.getAllValues().get(0);
View child = decorView.getChildAt(0);
assert (decorView.getChildCount() == 1);
assert (child == getService().getProvider().getView());
assert (child.getVisibility() == View.VISIBLE);
assert (child.getClipBounds().equals(rect));
WindowManager.LayoutParams param = params.getAllValues().get(0);
assert (param.x == 10);
assert (param.y == 20);
assert (param.width == 30);
assert (param.height == 40);
Mockito.verifyNoMoreInteractions(mWindowManagerMock);
}
});
}
}

View File

@ -0,0 +1,254 @@
/**
* Copyright (c) 2016, The CyanogenMod 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 org.cyanogenmod.tests.externalviews.keyguardexternalviews;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.test.AndroidTestCase;
import android.view.WindowManager;
import cyanogenmod.externalviews.IExternalViewProviderFactory;
import cyanogenmod.externalviews.IKeyguardExternalViewCallbacks;
import cyanogenmod.externalviews.IKeyguardExternalViewProvider;
import cyanogenmod.externalviews.KeyguardExternalView;
import org.cyanogenmod.tests.common.MockIBinderStubForInterface;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class KeyguardExternalViewTest extends AndroidTestCase {
private IKeyguardExternalViewProvider.Stub mIKeyguardExternalViewProvider;
private IExternalViewProviderFactory.Stub mExternalViewProviderFactory;
private WindowManager mWindowManagerMock;
private Context mContextMock;
private ServiceConnection mServiceConnection;
private IKeyguardExternalViewCallbacks mKeyguardCallback;
private KeyguardExternalView mExternalView;
@Override
protected void setUp() throws Exception {
super.setUp();
WindowManager windowManager = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
// Ensure we mock context but invoke non intercepted calls to impl
mContextMock = Mockito.mock(Context.class, Mockito.CALLS_REAL_METHODS);
// Needed since ExternalView's base class instantiates things off this.
// We can't use a spy here since ContextImpl is hidden (PowerMock ?)
// For now just redirect these to the test context
Mockito.doReturn(getContext().getApplicationInfo()).when(mContextMock).getApplicationInfo();
Mockito.doReturn(getContext().getResources()).when(mContextMock).getResources();
Mockito.doReturn(getContext().getTheme()).when(mContextMock).getTheme();
// Mock window manager to ensure we don't try to add the windows
mWindowManagerMock = Mockito.mock(WindowManager.class);
Mockito.doReturn(mWindowManagerMock).when(mContextMock).getSystemService(Context.WINDOW_SERVICE);
Mockito.doReturn(windowManager.getDefaultDisplay()).when(mWindowManagerMock).getDefaultDisplay();
// Mock the viewProvider/KeyguardView to keep track of callback invocations
mIKeyguardExternalViewProvider = MockIBinderStubForInterface
.getMockInterface(IKeyguardExternalViewProvider.Stub.class);
mExternalViewProviderFactory = MockIBinderStubForInterface
.getMockInterface(IExternalViewProviderFactory.Stub.class);
// Ensure we return our view provider when the factory is asked to create external view
Mockito.doReturn(mIKeyguardExternalViewProvider)
.when(mExternalViewProviderFactory)
.createExternalView(Mockito.any(Bundle.class));
// Store the callback object registered by the view
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
mKeyguardCallback = (IKeyguardExternalViewCallbacks) invocation.getArguments()[0];
return null;
}
}).when(mIKeyguardExternalViewProvider)
.registerCallback(Mockito.notNull(IKeyguardExternalViewCallbacks.class));
// Simulate bound service connection when bindService is invoked
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
ServiceConnection connection = (ServiceConnection) invocation.getArguments()[1];
connection.onServiceConnected(null, mExternalViewProviderFactory);
mServiceConnection = connection;
return true;
}
}).when(mContextMock).bindService(Mockito.any(Intent.class),
Mockito.any(ServiceConnection.class), Mockito.anyInt());
}
public void testValidServiceBind() {
mExternalView = new KeyguardExternalView(mContextMock, null, new ComponentName("", ""));
// Ensure we attempted to bind to the service
Mockito.verify(mContextMock, Mockito.times(1)).bindService(Mockito.any(Intent.class),
Mockito.any(ServiceConnection.class), Mockito.anyInt());
}
public void testInvalidServiceBind() {
mExternalView = new KeyguardExternalView(mContextMock, null, null);
// Ensure we did not attempt to bind to the service
Mockito.verify(mContextMock, Mockito.never()).bindService(Mockito.any(Intent.class),
Mockito.any(ServiceConnection.class), Mockito.anyInt());
}
public void testServiceAndCallbacksRegistered() throws RemoteException {
testValidServiceBind();
// Ensure a view was asked to be created
Mockito.verify(mExternalViewProviderFactory, Mockito.times(1))
.createExternalView(Mockito.any(Bundle.class));
// Ensure callbacks were registered
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1))
.registerCallback(Mockito.notNull(IKeyguardExternalViewCallbacks.class));
assertNotNull(mKeyguardCallback);
}
public void testServiceUnbindAndCallbacksUnRegistered() throws RemoteException {
testServiceAndCallbacksRegistered();
assertNotNull(mServiceConnection);
mServiceConnection.onServiceDisconnected(null);
// Ensure callbacks were registered
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1))
.unregisterCallback(Mockito.notNull(IKeyguardExternalViewCallbacks.class));
}
// Ensure provider is alerted view callbacks
public void testViewProviderCallbacks() throws RemoteException {
testServiceAndCallbacksRegistered();
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onKeyguardShowing(true);
Mockito.verify(mIKeyguardExternalViewProvider,
Mockito.times(1)).onKeyguardShowing(Mockito.anyBoolean());
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onAttachedToWindow();
Mockito.verify(mIKeyguardExternalViewProvider,
Mockito.times(1)).onAttach(Mockito.any(IBinder.class));
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onDetachedFromWindow();
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1)).onDetach();
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onBouncerShowing(true);
Mockito.verify(mIKeyguardExternalViewProvider,
Mockito.times(1)).onBouncerShowing(Mockito.anyBoolean());
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onKeyguardDismissed();
Mockito.verify(mIKeyguardExternalViewProvider,
Mockito.times(1)).onKeyguardDismissed();
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onLockscreenSlideOffsetChanged(1f);
Mockito.verify(mIKeyguardExternalViewProvider,
Mockito.times(1)).onLockscreenSlideOffsetChanged(Mockito.eq(1f));
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onScreenTurnedOff();
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1)).onScreenTurnedOff();
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.onScreenTurnedOn();
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1)).onScreenTurnedOn();
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
}
public void testWindowMovement() throws RemoteException {
testServiceAndCallbacksRegistered();
Mockito.reset(mIKeyguardExternalViewProvider);
mExternalView.setLeft(0);
mExternalView.setTop(0);
mExternalView.setRight(100);
mExternalView.setBottom(100);
mExternalView.onPreDraw();
Mockito.verify(mIKeyguardExternalViewProvider, Mockito.times(1))
.alterWindow(Mockito.eq(0), Mockito.eq(0), Mockito.anyInt(),
Mockito.anyInt(), Mockito.eq(true), Mockito.any(Rect.class));
Mockito.verifyNoMoreInteractions(mIKeyguardExternalViewProvider);
}
public void testWindowAttachmentCallbacks() throws RemoteException {
testServiceAndCallbacksRegistered();
KeyguardExternalView.OnWindowAttachmentChangedListener callback =
Mockito.mock(KeyguardExternalView.OnWindowAttachmentChangedListener.class);
mExternalView.registerOnWindowAttachmentChangedListener(callback);
mKeyguardCallback.onAttachedToWindow();
Mockito.verify(callback, Mockito.times(1)).onAttachedToWindow();
Mockito.verifyNoMoreInteractions(callback);
mKeyguardCallback.onDetachedFromWindow();
Mockito.verify(callback, Mockito.times(1)).onDetachedFromWindow();
Mockito.verifyNoMoreInteractions(callback);
}
public void testKeyguardViewCallbacks() throws RemoteException {
testServiceAndCallbacksRegistered();
KeyguardExternalView.KeyguardExternalViewCallbacks callback = Mockito.mock(
KeyguardExternalView.KeyguardExternalViewCallbacks.class);
mExternalView.registerKeyguardExternalViewCallback(callback);
mKeyguardCallback.requestDismiss();
Mockito.verify(callback, Mockito.times(1)).requestDismiss();
Mockito.verifyNoMoreInteractions(callback);
Intent i = new Intent();
mKeyguardCallback.requestDismissAndStartActivity(i);
Mockito.verify(callback, Mockito.times(1))
.requestDismissAndStartActivity(Mockito.eq(i));
Mockito.verifyNoMoreInteractions(callback);
mKeyguardCallback.setInteractivity(true);
assert(mExternalView.isInteractive());
Mockito.verifyNoMoreInteractions(callback);
mKeyguardCallback.slideLockscreenIn();
Mockito.verify(callback, Mockito.times(1)).slideLockscreenIn();
Mockito.verifyNoMoreInteractions(callback);
mExternalView.binderDied();
Mockito.verify(callback, Mockito.times(1)).providerDied();
Mockito.verifyNoMoreInteractions(callback);
}
}