aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src/org/lineageos
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/org/lineageos')
-rw-r--r--tests/src/org/lineageos/tests/LineageOSTestApplication.java37
-rw-r--r--tests/src/org/lineageos/tests/TestActivity.java63
-rw-r--r--tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java59
-rw-r--r--tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java200
-rw-r--r--tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java388
-rw-r--r--tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java60
-rw-r--r--tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java50
-rw-r--r--tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java152
-rw-r--r--tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java260
-rw-r--r--tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java111
-rw-r--r--tests/src/org/lineageos/tests/profiles/ProfileTest.java185
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java52
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java49
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java71
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java39
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java225
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java539
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java49
-rw-r--r--tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java58
-rw-r--r--tests/src/org/lineageos/tests/providers/LineageSettingsTest.java177
-rw-r--r--tests/src/org/lineageos/tests/util/ColorUtilTest.java123
-rw-r--r--tests/src/org/lineageos/tests/versioning/VersioningTest.java61
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java206
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/BuildTest.java67
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java26
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java108
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java55
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java131
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java107
-rw-r--r--tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java113
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java108
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java242
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java54
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java96
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java252
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java129
-rw-r--r--tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java303
37 files changed, 5005 insertions, 0 deletions
diff --git a/tests/src/org/lineageos/tests/LineageOSTestApplication.java b/tests/src/org/lineageos/tests/LineageOSTestApplication.java
new file mode 100644
index 00000000..0eb754e9
--- /dev/null
+++ b/tests/src/org/lineageos/tests/LineageOSTestApplication.java
@@ -0,0 +1,37 @@
+/**
+ * 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.lineageos.tests;
+
+import android.app.Application;
+import android.content.Context;
+
+/**
+ * Created by adnan on 2/4/16.
+ */
+public class LineageOSTestApplication extends Application {
+ private static Context sApplicationContext;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ sApplicationContext = getApplicationContext();
+ }
+
+ public static Context getStaticApplicationContext() {
+ return sApplicationContext;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/TestActivity.java b/tests/src/org/lineageos/tests/TestActivity.java
new file mode 100644
index 00000000..9c8d8604
--- /dev/null
+++ b/tests/src/org/lineageos/tests/TestActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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 org.lineageos.tests;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public abstract class TestActivity extends ListActivity
+{
+ Test[] mTests;
+
+ protected abstract String tag();
+ protected abstract Test[] tests();
+
+ protected abstract class Test {
+ protected String name;
+ protected Test(String n) {
+ name = n;
+ }
+ protected abstract void run();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mTests = tests();
+
+ String[] labels = new String[mTests.length];
+ for (int i=0; i<mTests.length; i++) {
+ labels[i] = mTests[i].name;
+ }
+
+ setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id)
+ {
+ Test t = mTests[position];
+ android.util.Log.d(tag(), "Test: " + t.name);
+ t.run();
+ }
+
+} \ No newline at end of file
diff --git a/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java b/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java
new file mode 100644
index 00000000..79c61744
--- /dev/null
+++ b/tests/src/org/lineageos/tests/common/MockIBinderStubForInterface.java
@@ -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.lineageos.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;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java b/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java
new file mode 100644
index 00000000..55807c5c
--- /dev/null
+++ b/tests/src/org/lineageos/tests/common/ThreadServiceTestCase.java
@@ -0,0 +1,200 @@
+package org.lineageos.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();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java b/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java
new file mode 100644
index 00000000..6d247473
--- /dev/null
+++ b/tests/src/org/lineageos/tests/hardware/LineageHardwareTest.java
@@ -0,0 +1,388 @@
+/**
+ * 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.lineageos.tests.hardware;
+
+import android.os.Bundle;
+
+import android.widget.Toast;
+
+import java.util.Arrays;
+import java.util.List;
+
+import lineageos.hardware.LineageHardwareManager;
+import lineageos.hardware.DisplayMode;
+
+import org.lineageos.tests.TestActivity;
+
+/**
+ * Created by adnan on 8/31/15.
+ */
+public class LineageHardwareTest extends TestActivity {
+ private LineageHardwareManager mHardwareManager;
+
+ private static final List<Integer> FEATURES = Arrays.asList(
+ LineageHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT,
+ LineageHardwareManager.FEATURE_COLOR_ENHANCEMENT,
+ LineageHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION,
+ LineageHardwareManager.FEATURE_DISPLAY_GAMMA_CALIBRATION,
+ LineageHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY,
+ LineageHardwareManager.FEATURE_KEY_DISABLE,
+ LineageHardwareManager.FEATURE_LONG_TERM_ORBITS,
+ LineageHardwareManager.FEATURE_SERIAL_NUMBER,
+ LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT,
+ LineageHardwareManager.FEATURE_TOUCH_HOVERING,
+ LineageHardwareManager.FEATURE_AUTO_CONTRAST,
+ LineageHardwareManager.FEATURE_DISPLAY_MODES,
+ LineageHardwareManager.FEATURE_PERSISTENT_STORAGE
+ );
+
+ private static final List<String> FEATURE_STRINGS = Arrays.asList(
+ "FEATURE_ADAPTIVE_BACKLIGHT",
+ "FEATURE_COLOR_ENHANCEMENT",
+ "FEATURE_DISPLAY_COLOR_CALIBRATION",
+ "FEATURE_DISPLAY_GAMMA_CALIBRATION",
+ "FEATURE_HIGH_TOUCH_SENSITIVITY",
+ "FEATURE_KEY_DISABLE",
+ "FEATURE_LONG_TERM_ORBITS",
+ "FEATURE_SERIAL_NUMBER",
+ "FEATURE_SUNLIGHT_ENHANCEMENT",
+ "FEATURE_TOUCH_HOVERING",
+ "FEATURE_AUTO_CONTRAST",
+ "FEATURE_DISPLAY_MODES",
+ "FEATURE_PERSISTENT_STORAGE"
+ );
+
+ private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
+ LineageHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT,
+ LineageHardwareManager.FEATURE_COLOR_ENHANCEMENT,
+ LineageHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY,
+ LineageHardwareManager.FEATURE_KEY_DISABLE,
+ LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT,
+ LineageHardwareManager.FEATURE_TOUCH_HOVERING,
+ LineageHardwareManager.FEATURE_AUTO_CONTRAST
+ );
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mHardwareManager = LineageHardwareManager.getInstance(this);
+ }
+
+ @Override
+ protected String tag() {
+ return null;
+ }
+
+ @Override
+ protected Test[] tests() {
+ return mTests;
+ }
+
+ private boolean vibratorSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_VIBRATOR)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean displayColorCalibrationSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Display Color Calibration not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean ltoSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_LONG_TERM_ORBITS)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Long Term Orbits not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean serialSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_SERIAL_NUMBER)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Serial number not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean uniqueDeviceIdSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_UNIQUE_DEVICE_ID)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Unique device ID not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean displayModesSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_DISPLAY_MODES)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Display modes not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private boolean persistentStorageSupported() {
+ if (mHardwareManager.isSupported(LineageHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
+ return true;
+ } else {
+ Toast.makeText(LineageHardwareTest.this, "Persistent storage not supported",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("Test get supported features") {
+ public void run() {
+ Toast.makeText(LineageHardwareTest.this, "Supported features " +
+ mHardwareManager.getSupportedFeatures(),
+ Toast.LENGTH_SHORT).show();
+ }
+ },
+ new Test("Test features supported") {
+ @Override
+ protected void run() {
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+ for (int feature : FEATURES) {
+ boolean supported = mHardwareManager.isSupported(feature);
+ if (mHardwareManager.isSupported(FEATURE_STRINGS.get(i)) != supported) {
+ throw new RuntimeException("Internal error, feature string lookup failed");
+ }
+ i++;
+ builder.append("Feature " + feature + "\n")
+ .append("is supported " + supported + "\n");
+ }
+ Toast.makeText(LineageHardwareTest.this, "Supported features " +
+ builder.toString(),
+ Toast.LENGTH_SHORT).show();
+ }
+ },
+ new Test("Test boolean features enabled") {
+ @Override
+ protected void run() {
+ StringBuilder builder = new StringBuilder();
+ for (int feature : BOOLEAN_FEATURES) {
+ builder.append("Feature " + feature + "\n")
+ .append("is enabled " + mHardwareManager.isSupported(feature)
+ + "\n");
+ }
+ Toast.makeText(LineageHardwareTest.this, "Features " +
+ builder.toString(),
+ Toast.LENGTH_SHORT).show();
+ }
+ },
+ new Test("Test get vibrator intensity") {
+ @Override
+ protected void run() {
+ if (vibratorSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator intensity " +
+ mHardwareManager.getVibratorIntensity(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test get vibrator default intensity") {
+ @Override
+ protected void run() {
+ if (vibratorSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator default intensity " +
+ mHardwareManager.getVibratorDefaultIntensity(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test get vibrator max intensity") {
+ @Override
+ protected void run() {
+ if (vibratorSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator max intensity " +
+ mHardwareManager.getVibratorMaxIntensity(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test get vibrator min intensity") {
+ @Override
+ protected void run() {
+ if (vibratorSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator min intensity " +
+ mHardwareManager.getVibratorMinIntensity(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test get vibrator min intensity") {
+ @Override
+ protected void run() {
+ if (vibratorSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Vibrator min intensity " +
+ mHardwareManager.getVibratorWarningIntensity(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Display Color Calibration") {
+ @Override
+ protected void run() {
+ if (displayColorCalibrationSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Display Color Calibration " +
+ mHardwareManager.getDisplayColorCalibration(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Default Display Color Calibration") {
+ @Override
+ protected void run() {
+ if (displayColorCalibrationSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Default Display Color Calibration " +
+ mHardwareManager.getDisplayColorCalibrationDefault(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Display Color Calibration Max") {
+ @Override
+ protected void run() {
+ if (displayColorCalibrationSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Display Color Calibration Max " +
+ mHardwareManager.getDisplayColorCalibrationMax(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Display Color Calibration Min") {
+ @Override
+ protected void run() {
+ if (displayColorCalibrationSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Display Color Calibration Min " +
+ mHardwareManager.getDisplayColorCalibrationMin(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Set Display Color Calibration") {
+ @Override
+ protected void run() {
+ if (displayColorCalibrationSupported()) {
+ mHardwareManager.setDisplayColorCalibration(new int[] {0,0,0});
+ }
+ }
+ },
+ new Test("Test Get Long Term Orbits Source") {
+ @Override
+ protected void run() {
+ if (ltoSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Source " +
+ mHardwareManager.getLtoSource(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Long Term Orbits Destination") {
+ @Override
+ protected void run() {
+ if (ltoSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Destination " +
+ mHardwareManager.getLtoDestination(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Long Term Orbits Interval") {
+ @Override
+ protected void run() {
+ if (ltoSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Long Term Orbit Download Interval " +
+ mHardwareManager.getLtoDownloadInterval(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Serial Number") {
+ @Override
+ protected void run() {
+ if (serialSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Serial number " +
+ mHardwareManager.getSerialNumber(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Unique Device ID") {
+ @Override
+ protected void run() {
+ if (uniqueDeviceIdSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Unique Device ID " +
+ mHardwareManager.getUniqueDeviceId(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Display Modes") {
+ @Override
+ protected void run() {
+ if (displayModesSupported()) {
+ StringBuilder builder = new StringBuilder();
+ for (DisplayMode displayMode : mHardwareManager.getDisplayModes()) {
+ builder.append("Display mode " + displayMode.name + "\n");
+ }
+ Toast.makeText(LineageHardwareTest.this, "Display modes: \n"
+ + builder.toString(), Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Current Display Mode") {
+ @Override
+ protected void run() {
+ if (displayModesSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Default Display Mode " +
+ mHardwareManager.getCurrentDisplayMode(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ new Test("Test Get Default Display Mode") {
+ @Override
+ protected void run() {
+ if (displayModesSupported()) {
+ Toast.makeText(LineageHardwareTest.this, "Default Display Mode " +
+ mHardwareManager.getCurrentDisplayMode(),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ },
+ };
+}
diff --git a/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java b/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java
new file mode 100644
index 00000000..01a24771
--- /dev/null
+++ b/tests/src/org/lineageos/tests/hardware/unit/DisplayModeTest.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.hardware.unit;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.app.LineageContextConstants;
+import lineageos.hardware.DisplayMode;
+
+/**
+ * Created by adnan on 9/1/15.
+ */
+public class DisplayModeTest extends AndroidTestCase {
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Only run this if we support hardware abstraction
+ org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.HARDWARE_ABSTRACTION));
+ }
+
+ @SmallTest
+ public void testDisplayModeUnravelFromParcel() {
+ int expectedId = 1337;
+ String expectedName = "test";
+ DisplayMode expectedDisplayMode = new DisplayMode(expectedId, expectedName);
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ expectedDisplayMode.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ DisplayMode fromParcel = DisplayMode.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(expectedDisplayMode.id);
+ assertNotNull(expectedDisplayMode.name);
+
+ assertEquals(expectedDisplayMode.id, fromParcel.id );
+ assertEquals(expectedDisplayMode.name,
+ fromParcel.name);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java b/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java
new file mode 100644
index 00000000..01a8145f
--- /dev/null
+++ b/tests/src/org/lineageos/tests/hardware/unit/LineageHardwareManagerTest.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.hardware.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.hardware.LineageHardwareManager;
+import lineageos.hardware.ILineageHardwareService;
+
+/**
+ * Created by adnan on 9/1/15.
+ */
+public class LineageHardwareManagerTest extends AndroidTestCase {
+ private LineageHardwareManager mLineageHardwareManager;
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Only run this if we support hardware abstraction
+ org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.HARDWARE_ABSTRACTION));
+ mLineageHardwareManager = LineageHardwareManager.getInstance(mContext);
+ }
+
+ @SmallTest
+ public void testManagerExists() {
+ assertNotNull(mLineageHardwareManager);
+ }
+
+ @SmallTest
+ public void testManagerServiceIsAvailable() {
+ ILineageHardwareService ilineageStatusBarManager = mLineageHardwareManager.getService();
+ assertNotNull(ilineageStatusBarManager);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java b/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java
new file mode 100644
index 00000000..2f0eec9c
--- /dev/null
+++ b/tests/src/org/lineageos/tests/hardware/unit/LiveDisplayManagerTest.java
@@ -0,0 +1,152 @@
+package org.lineageos.tests.hardware.unit;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Assume;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.hardware.LineageHardwareManager;
+import lineageos.hardware.ILiveDisplayService;
+import lineageos.hardware.LiveDisplayConfig;
+import lineageos.hardware.LiveDisplayManager;
+import lineageos.util.ColorUtils;
+
+public class LiveDisplayManagerTest extends AndroidTestCase {
+
+ private static final String TAG = "LiveDisplayManagerTest";
+
+ private LiveDisplayManager mLiveDisplay;
+ private LineageHardwareManager mHardware;
+
+ private PowerManager mPower;
+ private PowerManager.WakeLock mWakeLock;
+
+ private LiveDisplayConfig mConfig;
+ private int mInitialMode;
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.LIVEDISPLAY));
+
+ mLiveDisplay = LiveDisplayManager.getInstance(mContext);
+ if (mLiveDisplay.getConfig().hasModeSupport()) {
+ mInitialMode = mLiveDisplay.getMode();
+ }
+ mConfig = mLiveDisplay.getConfig();
+
+ mHardware = LineageHardwareManager.getInstance(mContext);
+ mPower = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPower.newWakeLock(
+ PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
+ mWakeLock.acquire();
+ }
+
+ @Override
+ protected void tearDown() {
+ mLiveDisplay.setMode(mInitialMode);
+ mWakeLock.release();
+ }
+
+ @SmallTest
+ public void testManagerExists() {
+ assertNotNull(mLiveDisplay);
+ }
+
+ @SmallTest
+ public void testManagerServiceIsAvailable() {
+ ILiveDisplayService service = LiveDisplayManager.getService();
+ assertNotNull(service);
+ }
+
+ @SmallTest
+ public void testConfig() {
+ assertNotNull(mConfig);
+
+ // at least GPU mode should be available
+ assertTrue(mConfig.isAvailable());
+ }
+
+ @SmallTest
+ public void testNightMode() throws Exception {
+ Assume.assumeTrue(mConfig.hasModeSupport());
+
+ int day = mLiveDisplay.getDayColorTemperature();
+ int night = mLiveDisplay.getNightColorTemperature();
+
+ mLiveDisplay.setMode(LiveDisplayManager.MODE_NIGHT);
+ assertColorTemperature(night);
+
+ // custom value
+ mLiveDisplay.setNightColorTemperature(3300);
+ assertColorTemperature(3300);
+
+ // "default"
+ mLiveDisplay.setNightColorTemperature(mConfig.getDefaultNightTemperature());
+ assertColorTemperature(mConfig.getDefaultNightTemperature());
+
+ mLiveDisplay.setNightColorTemperature(night);
+
+ // day should not have changed
+ assertEquals(day, mLiveDisplay.getDayColorTemperature());
+ }
+
+ @SmallTest
+ public void testDayMode() throws Exception {
+ Assume.assumeTrue(mConfig.hasModeSupport());
+
+ int day = mLiveDisplay.getDayColorTemperature();
+ int night = mLiveDisplay.getNightColorTemperature();
+
+ mLiveDisplay.setMode(LiveDisplayManager.MODE_DAY);
+ assertColorTemperature(day);
+
+ // custom value
+ mLiveDisplay.setDayColorTemperature(8000);
+ assertColorTemperature(8000);
+
+ // "default"
+ mLiveDisplay.setDayColorTemperature(mConfig.getDefaultDayTemperature());
+ assertColorTemperature(mConfig.getDefaultDayTemperature());
+
+ mLiveDisplay.setDayColorTemperature(day);
+
+ // night should not have changed
+ assertEquals(night, mLiveDisplay.getNightColorTemperature());
+ }
+
+ @SmallTest
+ public void testOutdoorMode() throws Exception {
+ Assume.assumeTrue(mConfig.hasFeature(LiveDisplayManager.MODE_OUTDOOR));
+
+ assertTrue(mHardware.isSupported(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT));
+
+ mLiveDisplay.setMode(LiveDisplayManager.MODE_OUTDOOR);
+ Thread.sleep(1000);
+ assertTrue(mHardware.get(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT));
+
+ mLiveDisplay.setMode(LiveDisplayManager.MODE_OFF);
+ Thread.sleep(1000);
+ assertFalse(mHardware.get(LineageHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT));
+ }
+
+ private void assertColorTemperature(int degK) throws Exception {
+ Thread.sleep(2000);
+ assertEquals(degK, LiveDisplayManager.getService().getColorTemperature());
+ checkHardwareValue(ColorUtils.temperatureToRGB(degK));
+ }
+
+ private void checkHardwareValue(float[] expected) {
+ int[] hardware = mHardware.getDisplayColorCalibration();
+ int max = mHardware.getDisplayColorCalibrationMax();
+ assertEquals((int)Math.floor(expected[0] * max), hardware[0]);
+ assertEquals((int)Math.floor(expected[1] * max), hardware[1]);
+ assertEquals((int)Math.floor(expected[2] * max), hardware[2]);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java b/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java
new file mode 100644
index 00000000..e35d3c88
--- /dev/null
+++ b/tests/src/org/lineageos/tests/media/unit/LineageAudioManagerTest.java
@@ -0,0 +1,260 @@
+/*
+ * 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.lineageos.tests.media.unit;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import org.junit.Assume;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.media.AudioSessionInfo;
+import lineageos.media.LineageAudioManager;
+import lineageos.media.ILineageAudioService;
+
+public class LineageAudioManagerTest extends AndroidTestCase {
+
+ private static final String TAG = "LineageAudioManagerTest";
+
+ private LineageAudioManager mLineageAudioManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.AUDIO));
+
+ mLineageAudioManager = LineageAudioManager.getInstance(mContext);
+ }
+
+ /**
+ * EXPECT: The platform should return a valid manager instance.
+ */
+ @SmallTest
+ public void testManagerExists() {
+ assertNotNull(mLineageAudioManager);
+ }
+
+ /**
+ * EXPECT: The service in the manager should also be valid.
+ */
+ @SmallTest
+ public void testManagerServiceIsAvailable() {
+ ILineageAudioService service = LineageAudioManager.getService();
+ assertNotNull(service);
+ }
+
+ /**
+ * EXPECT: listAudioSessions should be populated when a new stream is
+ * created, and it's session ID should match what AudioTrack says it is.
+ *
+ * We simply create an audio track, and query the policy for sessions.
+ */
+ @SmallTest
+ public void testSessionList() {
+
+ AudioTrack track = createTestTrack();
+ int session = track.getAudioSessionId();
+
+ AudioSessionInfo info = findAudioSessionInfo(session);
+ assertNotNull(info);
+ assertEquals(session, info.getSessionId());
+ assertEquals(3, info.getChannelMask());
+
+ track.release();
+
+ info = findAudioSessionInfo(session);
+ assertNull(info);
+ }
+
+ /**
+ * EXPECT: LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED should be broadcast when
+ * audio sessions are opened and closed.
+ *
+ * We register a receiver for the broadcast, create an AudioTrack, and wait to
+ * observe both the open and close session events. The info in the returned
+ * AudioSessionInfo should match our expectations.
+ */
+ @SmallTest
+ public void testSessionInfoBroadcast() throws Exception {
+
+ IntentFilter filter = new IntentFilter(LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED);
+ AudioSessionReceiver receiver = new AudioSessionReceiver(2);
+ mContext.registerReceiver(receiver, filter);
+
+ AudioTrack track = createTestTrack();
+ track.play();
+ track.release();
+
+ receiver.waitForSessions();
+
+ mContext.unregisterReceiver(receiver);
+
+ assertEquals(1, receiver.getNumAdded());
+ assertEquals(1, receiver.getNumRemoved());
+
+ assertEquals(1, receiver.getSessions().size());
+
+ AudioSessionInfo info = receiver.getSessions().get(0);
+ assertNotNull(info);
+ assertNotNull(info.toString());
+ assertEquals(track.getAudioSessionId(), info.getSessionId());
+ assertEquals(3, info.getChannelMask());
+ assertEquals(AudioManager.STREAM_MUSIC, info.getStream());
+
+ }
+
+ private static final int SESSIONS = 50;
+
+ /**
+ * EXPECT: The ACTION_AUDIO_SESSIONS_CHANGED broadcast and associated backend should
+ * be resilent to multithreaded and/or aggressive/destructive usage. A single add
+ * and a single remove event should be broadcast for the lifecycle of a stream.
+ *
+ * We register a receiver for session events, spawn a small thread pool, and create
+ * up to SESSIONS AudioTracks and play + release them on the thread. A small delay
+ * is inserted to prevent AudioFlinger from running out of tracks. Once the expected
+ * number of sessions arrives, we verify our expectation regarding event counts,
+ * and additionally verify that all the session ids we saw when creating our
+ * AudioTracks were returned in the AudioSessionInfo broadcasts.
+ */
+ @SmallTest
+ public void testSymphonyOfDestruction() throws Exception {
+ IntentFilter filter = new IntentFilter(LineageAudioManager.ACTION_AUDIO_SESSIONS_CHANGED);
+ AudioSessionReceiver receiver = new AudioSessionReceiver(SESSIONS * 2);
+ mContext.registerReceiver(receiver, filter);
+
+ final List<Integer> sessions = new ArrayList<Integer>();
+
+ ExecutorService sexecutioner = Executors.newFixedThreadPool(5);
+ for (int i = 0; i < SESSIONS; i++) {
+ sexecutioner.submit(new Runnable() {
+ @Override
+ public void run() {
+ AudioTrack track = createTestTrack();
+ synchronized (sessions) {
+ sessions.add(track.getAudioSessionId());
+ }
+ track.play();
+ track.release();
+ }
+ });
+ if ((i % 2) == 0) {
+ Thread.sleep(100);
+ }
+ }
+
+ receiver.waitForSessions();
+ sexecutioner.shutdown();
+
+ assertEquals(SESSIONS, sessions.size());
+ assertEquals(SESSIONS, receiver.getNumAdded());
+ assertEquals(SESSIONS, receiver.getNumRemoved());
+
+ for (AudioSessionInfo info : receiver.getSessions()) {
+ assertTrue(sessions.contains(info.getSessionId()));
+ }
+ }
+
+ private static class AudioSessionReceiver extends BroadcastReceiver {
+
+ private int mAdded = 0;
+ private int mRemoved = 0;
+
+ private final CountDownLatch mLatch;
+
+ private List<AudioSessionInfo> mSessions = new ArrayList<AudioSessionInfo>();
+
+ public AudioSessionReceiver(int count) {
+ mLatch = new CountDownLatch(count);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ assertNotNull(intent);
+
+ boolean added = intent.getBooleanExtra(LineageAudioManager.EXTRA_SESSION_ADDED, false);
+
+ AudioSessionInfo info = intent.getParcelableExtra(LineageAudioManager.EXTRA_SESSION_INFO);
+ Log.d(TAG, "onReceive: " + info);
+
+ assertNotNull(info);
+
+ synchronized (mSessions) {
+ if (added) {
+ mAdded++;
+ mSessions.add(info);
+ } else {
+ mRemoved++;
+ }
+ }
+
+ mLatch.countDown();
+ }
+
+ public int getNumAdded() {
+ return mAdded;
+ }
+
+ public int getNumRemoved() {
+ return mRemoved;
+ }
+
+ public List<AudioSessionInfo> getSessions() {
+ return mSessions;
+ }
+
+ public void waitForSessions() throws InterruptedException {
+ mLatch.await(60, TimeUnit.SECONDS);
+ }
+ };
+
+ private AudioSessionInfo findAudioSessionInfo(int sessionId) {
+ List<AudioSessionInfo> infos = mLineageAudioManager.listAudioSessions(AudioManager.STREAM_MUSIC);
+ for (AudioSessionInfo info : infos) {
+ if (info.getSessionId() == sessionId) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ private AudioTrack createTestTrack() {
+ int bytes = 2 * 44100 / 1000;
+ AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
+ AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.ENCODING_PCM_16BIT,
+ bytes,
+ AudioTrack.STATE_INITIALIZED);
+ return track;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java b/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java
new file mode 100644
index 00000000..4259ef62
--- /dev/null
+++ b/tests/src/org/lineageos/tests/power/unit/PerfomanceManagerTest.java
@@ -0,0 +1,111 @@
+/**
+ * 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.lineageos.tests.power.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.power.IPerformanceManager;
+import lineageos.power.PerformanceManager;
+import lineageos.power.PerformanceProfile;
+
+/**
+ * Code coverage for public facing {@link PerformanceManager} interfaces.
+ * The test below will save and restore the current performance profile to
+ * not impact successive tests.
+ */
+public class PerfomanceManagerTest extends AndroidTestCase {
+ private static final String TAG = PerfomanceManagerTest.class.getSimpleName();
+ private static final int IMPOSSIBLE_POWER_PROFILE = -1;
+ private PerformanceManager mLineagePerformanceManager;
+ private PerformanceProfile mSavedPerfProfile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Only run this if we support performance abstraction
+ org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.PERFORMANCE));
+ mLineagePerformanceManager = PerformanceManager.getInstance(mContext);
+ // Save the perf profile for later restore.
+ mSavedPerfProfile = mLineagePerformanceManager.getPowerProfile(
+ mLineagePerformanceManager.getPowerProfile());
+ }
+
+ @SmallTest
+ public void testManagerExists() {
+ assertNotNull(mLineagePerformanceManager);
+ }
+
+ @SmallTest
+ public void testManagerServiceIsAvailable() {
+ IPerformanceManager ilineageStatusBarManager = mLineagePerformanceManager.getService();
+ assertNotNull(ilineageStatusBarManager);
+ }
+
+ @SmallTest
+ public void testPowerProfileCantBeSetIfNoneSupported() {
+ // Assert that if we attempt to set a power profile if none supported
+ // then we receive a failed response from the service.
+ if (mLineagePerformanceManager.getNumberOfProfiles() == 0) {
+ for (int powerProfile = 0; powerProfile <
+ PerformanceManager.POSSIBLE_POWER_PROFILES.length; powerProfile++) {
+ assertFalse(mLineagePerformanceManager.setPowerProfile(powerProfile));
+ }
+ }
+ }
+
+ @SmallTest
+ public void testGetPowerProfile() {
+ assertNotSame(IMPOSSIBLE_POWER_PROFILE, mSavedPerfProfile);
+ }
+
+ @SmallTest
+ public void testSetAndGetPowerProfile() {
+ // Identify what power profiles are supported. The api currently returns
+ // the total number of profiles supported in an ordered manner, thus we can
+ // assume what they are and if we can set everything correctly.
+ // TODO: Don't skip powersave. Skipped due to powersave being ignored while device plugged
+ for (int powerProfile = 1; powerProfile <
+ PerformanceManager.POSSIBLE_POWER_PROFILES.length; powerProfile++) {
+ if (powerProfile < mLineagePerformanceManager.getNumberOfProfiles()) {
+ //It is supported, set it and test if it was set
+ if (mLineagePerformanceManager.getPowerProfile() != powerProfile) {
+ mLineagePerformanceManager.setPowerProfile(powerProfile);
+ // Verify that it was set correctly.
+ assertEquals(powerProfile, mLineagePerformanceManager.getPowerProfile());
+ }
+ } else {
+ assertFalse(mLineagePerformanceManager.setPowerProfile(powerProfile));
+ }
+ }
+ }
+
+ @SmallTest
+ public void testGetPerfProfileHasAppProfiles() {
+ // No application has power save by default
+ assertEquals(false, mLineagePerformanceManager.getProfileHasAppProfiles(
+ PerformanceManager.PROFILE_POWER_SAVE));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ // Reset
+ mLineagePerformanceManager.setPowerProfile(mSavedPerfProfile.getId());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/ProfileTest.java b/tests/src/org/lineageos/tests/profiles/ProfileTest.java
new file mode 100644
index 00000000..1e77538d
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/ProfileTest.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.profiles;
+
+import android.media.AudioManager;
+import android.os.Bundle;
+
+import lineageos.app.Profile;
+import lineageos.app.Profile.Type;
+
+import lineageos.app.ProfileManager;
+import lineageos.profiles.AirplaneModeSettings;
+import lineageos.profiles.BrightnessSettings;
+import lineageos.profiles.ConnectionSettings;
+import lineageos.profiles.LockSettings;
+import lineageos.profiles.RingModeSettings;
+import lineageos.profiles.StreamSettings;
+import org.lineageos.tests.TestActivity;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+/**
+ * Created by adnan on 6/26/15.
+ */
+public class ProfileTest extends TestActivity {
+ private ProfileManager mProfileManager;
+ private ArrayList<UUID> mProfileUuidList;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mProfileManager = ProfileManager.getInstance(this);
+ mProfileUuidList = new ArrayList<UUID>();
+ }
+
+ @Override
+ protected Test[] tests() {
+ return mTests;
+ }
+
+ @Override
+ protected String tag() {
+ return null;
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("test create random Profile") {
+ public void run() {
+ Profile profile = new Profile("Test Profile");
+ profile.setProfileType(Type.TOGGLE);
+ profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE);
+ profile.setDozeMode(Profile.DozeMode.DEFAULT);
+ profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE));
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ }
+ },
+ new Test("test add static Profile") {
+ public void run() {
+ Profile profile = new Profile("Test Profile-Active",
+ 0, UUID.fromString("65cd0d0c-1c42-11e5-9a21-1697f925ec7b"));
+ profile.setProfileType(Type.TOGGLE);
+ profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE);
+ profile.setDozeMode(Profile.DozeMode.DEFAULT);
+ profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE));
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test remove static Profile") {
+ public void run() {
+ mProfileManager.removeProfile(
+ mProfileManager.getProfile("65cd0d0c-1c42-11e5-9a21-1697f925ec7b"));
+ }
+ },
+ new Test("test create Profile and Set Active") {
+ public void run() {
+ Profile profile = new Profile("Test Profile-Active");
+ profile.setProfileType(Type.TOGGLE);
+ profile.setExpandedDesktopMode(Profile.ExpandedDesktopMode.ENABLE);
+ profile.setDozeMode(Profile.DozeMode.DEFAULT);
+ profile.setScreenLockMode(new LockSettings(Profile.LockMode.DISABLE));
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test create Profile, override airplane settings, and set active") {
+ @Override
+ protected void run() {
+ Profile profile = new Profile("Test Profile-Override-AIR-Active");
+ profile.setProfileType(Type.TOGGLE);
+ AirplaneModeSettings airplaneModeSettings =
+ new AirplaneModeSettings(
+ AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ profile.setAirplaneMode(airplaneModeSettings);
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test create Profile, override ring stream settings, and set active") {
+ @Override
+ protected void run() {
+ Profile profile = new Profile("Test Profile-Override-RNG-Active");
+ profile.setProfileType(Type.TOGGLE);
+ StreamSettings streamSettings =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ profile.setStreamSettings(streamSettings);
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test create Profile, override BT connection settings, and set active") {
+ @Override
+ protected void run() {
+ Profile profile = new Profile("Test Profile-Override-CNNCT-Active");
+ profile.setProfileType(Type.TOGGLE);
+ ConnectionSettings connectionSettings =
+ new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH,
+ ConnectionSettings.BooleanState.STATE_ENABLED, true);
+ profile.setConnectionSettings(connectionSettings);
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test create Profile, override brightness settings, and set active") {
+ @Override
+ protected void run() {
+ Profile profile = new Profile("Test Profile-Override-BRGHT-Active");
+ profile.setProfileType(Type.TOGGLE);
+ BrightnessSettings brightnessSettings =
+ new BrightnessSettings(0, true);
+ profile.setBrightness(brightnessSettings);
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("test create Profile, override ringmode settings, and set active") {
+ @Override
+ protected void run() {
+ Profile profile = new Profile("Test Profile-Override-RNGMD-Active");
+ profile.setProfileType(Type.TOGGLE);
+ RingModeSettings ringSettings = new RingModeSettings(
+ RingModeSettings.RING_MODE_MUTE, true);
+ profile.setRingMode(ringSettings);
+ mProfileUuidList.add(profile.getUuid());
+ mProfileManager.addProfile(profile);
+ mProfileManager.setActiveProfile(profile.getUuid());
+ }
+ },
+ new Test("Reset All") {
+ @Override
+ protected void run() {
+ // make sure we remove our own
+ for (UUID uuid: mProfileUuidList) {
+ Profile profile = mProfileManager.getProfile(uuid);
+ if (profile != null) {
+ mProfileManager.removeProfile(profile);
+ }
+ }
+ mProfileManager.resetAll();
+ }
+ }
+ };
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java
new file mode 100644
index 00000000..25a0fb1e
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/AirplaneModeSettingsTest.java
@@ -0,0 +1,52 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.profiles.AirplaneModeSettings;
+
+public class AirplaneModeSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructWholly() {
+ AirplaneModeSettings airplaneModeSettings =
+ new AirplaneModeSettings(
+ AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ assertEquals(AirplaneModeSettings.BooleanState.STATE_ENABLED, airplaneModeSettings.getValue());
+ assertEquals(true, airplaneModeSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyOverride() {
+ AirplaneModeSettings airplaneModeSettings =
+ new AirplaneModeSettings(
+ AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ airplaneModeSettings.setOverride(false);
+ assertEquals(false, airplaneModeSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ int expectedValue = AirplaneModeSettings.BooleanState.STATE_DISALED;
+ AirplaneModeSettings airplaneModeSettings =
+ new AirplaneModeSettings(
+ AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ airplaneModeSettings.setValue(expectedValue);
+ assertEquals(expectedValue, airplaneModeSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java
new file mode 100644
index 00000000..73814d88
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/BrightnessSettingsTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.profiles.BrightnessSettings;
+
+public class BrightnessSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructWholly() {
+ BrightnessSettings brightnessSettings =
+ new BrightnessSettings(0, true);
+ assertEquals(0, brightnessSettings.getValue());
+ assertEquals(true, brightnessSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyOverride() {
+ BrightnessSettings brightnessSettings =
+ new BrightnessSettings(0, true);
+ brightnessSettings.setOverride(false);
+ assertEquals(false, brightnessSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ int expectedValue = 30;
+ BrightnessSettings brightnessSettings =
+ new BrightnessSettings(0, true);
+ brightnessSettings.setValue(expectedValue);
+ assertEquals(expectedValue, brightnessSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java
new file mode 100644
index 00000000..4564727e
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/ConnectionSettingsTest.java
@@ -0,0 +1,71 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.profiles.ConnectionSettings;
+
+public class ConnectionSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructManually() {
+ ConnectionSettings connectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_GPS);
+ assertEquals(ConnectionSettings.PROFILE_CONNECTION_GPS,
+ connectionSettings.getConnectionId());
+ assertNotNull(connectionSettings);
+ }
+
+ @SmallTest
+ public void testConstructWholly() {
+ ConnectionSettings connectionSettings =
+ new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_GPS,
+ ConnectionSettings.BooleanState.STATE_DISALED, true);
+ assertEquals(true, connectionSettings.isOverride());
+ assertEquals(ConnectionSettings.BooleanState.STATE_DISALED,
+ connectionSettings.getValue());
+ assertEquals(ConnectionSettings.PROFILE_CONNECTION_GPS,
+ connectionSettings.getConnectionId());
+ assertNotNull(connectionSettings);
+ }
+
+ @SmallTest
+ public void testVerifyOverride() {
+ ConnectionSettings connectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_GPS);
+ connectionSettings.setOverride(true);
+ assertEquals(true, connectionSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifySubId() {
+ int expectedSubId = 2;
+ ConnectionSettings connectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_2G3G4G);
+ connectionSettings.setSubId(expectedSubId);
+ assertEquals(expectedSubId, connectionSettings.getSubId());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ int expectedValue = ConnectionSettings.BooleanState.STATE_DISALED;
+ ConnectionSettings connectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_2G3G4G);
+ connectionSettings.setValue(expectedValue);
+ assertEquals(expectedValue, connectionSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java
new file mode 100644
index 00000000..f3a47570
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/LockSettingsTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.app.Profile;
+import lineageos.profiles.LockSettings;
+
+public class LockSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructWholly() {
+ LockSettings lockSettings = new LockSettings(Profile.LockMode.INSECURE);
+ assertEquals(Profile.LockMode.INSECURE, lockSettings.getValue());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ int expectedValue = Profile.LockMode.DEFAULT;
+ LockSettings lockSettings = new LockSettings(Profile.LockMode.INSECURE);
+ lockSettings.setValue(expectedValue);
+ assertEquals(expectedValue, lockSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java b/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java
new file mode 100644
index 00000000..c507e80b
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/ProfileManagerTest.java
@@ -0,0 +1,225 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.profiles.unit;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import lineageos.app.LineageContextConstants;
+import lineageos.app.Profile;
+import lineageos.app.ProfileManager;
+import lineageos.app.IProfileManager;
+import lineageos.providers.LineageSettings;
+
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+public class ProfileManagerTest extends AndroidTestCase {
+ private static final String TAG = ProfileManagerTest.class.getSimpleName();
+ private static final int COUNTDOWN = 1;
+ private ProfileManager mProfileManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mProfileManager = ProfileManager.getInstance(mContext);
+ // Only run this if we support profiles service
+ org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.PROFILES));
+ }
+
+ @SmallTest
+ public void testManagerExists() {
+ assertNotNull(mProfileManager);
+ }
+
+ @SmallTest
+ public void testManagerServiceIsAvailable() {
+ IProfileManager iProfileManager = mProfileManager.getService();
+ assertNotNull(iProfileManager);
+ }
+
+ @SmallTest
+ public void testManagerProfileIsEnabled() {
+ // first enable profiles
+ final String enabledValue = "1";
+ assertTrue(LineageSettings.System.putString(getContext().getContentResolver(),
+ LineageSettings.System.SYSTEM_PROFILES_ENABLED, enabledValue));
+
+ // check that we successfully enabled them via system setting
+ assertEquals(enabledValue, LineageSettings.System.getString(getContext().getContentResolver(),
+ LineageSettings.System.SYSTEM_PROFILES_ENABLED));
+
+ // check that profile manger returns true
+ assertTrue(mProfileManager.isProfilesEnabled());
+
+ // now disable the setting
+ final String disabledValue = "0";
+ assertTrue(LineageSettings.System.putString(getContext().getContentResolver(),
+ LineageSettings.System.SYSTEM_PROFILES_ENABLED, disabledValue));
+
+ // check that we successfully disable them via system setting
+ assertEquals(disabledValue, LineageSettings.System.getString(getContext().getContentResolver(),
+ LineageSettings.System.SYSTEM_PROFILES_ENABLED));
+
+ assertFalse(mProfileManager.isProfilesEnabled());
+ }
+
+ private void ensureProfilesEnabled() {
+ final String enabledValue = "1";
+ assertTrue(LineageSettings.System.putString(getContext().getContentResolver(),
+ LineageSettings.System.SYSTEM_PROFILES_ENABLED, enabledValue));
+ }
+
+ @SmallTest
+ public void testGetActiveProfile() {
+ ensureProfilesEnabled();
+ final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
+ final Profile expectedActiveProfile = new Profile("TEST ACTIVE PROFILE");
+ mProfileManager.addProfile(expectedActiveProfile);
+
+ BroadcastReceiver intentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ signal.countDown();
+ }
+ };
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ProfileManager.INTENT_ACTION_PROFILE_SELECTED);
+ intentFilter.addAction(ProfileManager.INTENT_ACTION_PROFILE_UPDATED);
+
+ mContext.registerReceiver(intentReceiver, intentFilter);
+
+ mProfileManager.setActiveProfile(expectedActiveProfile.getName());
+
+ // Lock
+ try {
+ signal.await();
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+
+ assertEquals(expectedActiveProfile.getName(),
+ mProfileManager.getActiveProfile().getName());
+ mProfileManager.resetAll();
+
+ mContext.unregisterReceiver(intentReceiver);
+ }
+
+ @SmallTest
+ public void testGetProfileNames() {
+ ensureProfilesEnabled();
+ String[] expectedProfileNames = new String[5];
+ // These defaults are pulled from the default xml in the lineage platform resource package
+ Profile expectedProfile1 = mProfileManager.getProfile(
+ UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449"));
+ Profile expectedProfile2 = mProfileManager.getProfile(
+ UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655"));
+ Profile expectedProfile3 = mProfileManager.getProfile(
+ UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1"));
+
+ // Add extras
+ Profile expectedProfile4 = new Profile("PROFILE 1");
+ Profile expectedProfile5 = new Profile("PROFILE 2");
+
+ expectedProfileNames[0] = expectedProfile1.getName();
+ expectedProfileNames[1] = expectedProfile2.getName();
+ expectedProfileNames[2] = expectedProfile3.getName();
+ expectedProfileNames[3] = expectedProfile4.getName();
+ expectedProfileNames[4] = expectedProfile5.getName();
+
+ mProfileManager.addProfile(expectedProfile1);
+ mProfileManager.addProfile(expectedProfile2);
+
+ String[] actualProfileNames = mProfileManager.getProfileNames();
+ for (int i = 0; i < actualProfileNames.length; i++) {
+ assertEquals(expectedProfileNames[i], actualProfileNames[i]);
+ }
+ mProfileManager.resetAll();
+ }
+
+ @SmallTest
+ public void testGetProfiles() {
+ ensureProfilesEnabled();
+ Profile[] expectedProfiles = new Profile[5];
+ // These defaults are pulled from the default xml in the lineage platform resource package
+ Profile expectedProfile1 = mProfileManager.getProfile(
+ UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449"));
+ Profile expectedProfile2 = mProfileManager.getProfile(
+ UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655"));
+ Profile expectedProfile3 = mProfileManager.getProfile(
+ UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1"));
+
+ // Add extras
+ Profile expectedProfile4 = new Profile("PROFILE 1");
+ Profile expectedProfile5 = new Profile("PROFILE 2");
+
+ expectedProfiles[0] = expectedProfile1;
+ expectedProfiles[1] = expectedProfile2;
+ expectedProfiles[2] = expectedProfile3;
+ expectedProfiles[3] = expectedProfile4;
+ expectedProfiles[4] = expectedProfile5;
+
+ // The actual results come back in alphabetical order, :/
+ Arrays.sort(expectedProfiles);
+
+ mProfileManager.addProfile(expectedProfile4);
+ mProfileManager.addProfile(expectedProfile5);
+
+ Profile[] actualProfiles = mProfileManager.getProfiles();
+ for (int i = 0; i < actualProfiles.length; i++) {
+ assertEquals(expectedProfiles[i].getName(), actualProfiles[i].getName());
+ }
+ mProfileManager.resetAll();
+ }
+
+ @SmallTest
+ public void testProfileExists() {
+ ensureProfilesEnabled();
+ assertTrue(mProfileManager.profileExists(
+ UUID.fromString("6a181391-12ef-4f43-a701-32b11ed69449")));
+ assertTrue(mProfileManager.profileExists(
+ UUID.fromString("0230226d-0d05-494a-a9bd-d222a1117655")));
+ assertTrue(mProfileManager.profileExists(
+ UUID.fromString("e4e77d03-82ce-4417-9257-7d6c9ffb8fd1")));
+ String expectedProfileName = "PROFILE 1";
+ Profile expectedProfile = new Profile(expectedProfileName);
+ mProfileManager.addProfile(expectedProfile);
+ assertTrue(mProfileManager.profileExists(expectedProfileName));
+ mProfileManager.resetAll();
+ }
+
+ @SmallTest
+ public void testUpdateProfile() {
+ ensureProfilesEnabled();
+ String originalProfileName = "PROFILE 1";
+ String expectedProfileName = "PROFILE 2";
+ Profile expectedProfile = new Profile(originalProfileName);
+ mProfileManager.addProfile(expectedProfile);
+ expectedProfile.setName(expectedProfileName);
+ mProfileManager.updateProfile(expectedProfile);
+ assertNotSame(originalProfileName, expectedProfile.getName());
+ assertEquals(expectedProfileName, expectedProfile.getName());
+ mProfileManager.resetAll();
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java b/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java
new file mode 100644
index 00000000..899b0066
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/ProfileTest.java
@@ -0,0 +1,539 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.profiles.unit;
+
+import android.media.AudioManager;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.app.Profile;
+import lineageos.profiles.AirplaneModeSettings;
+import lineageos.profiles.BrightnessSettings;
+import lineageos.profiles.ConnectionSettings;
+import lineageos.profiles.LockSettings;
+import lineageos.profiles.RingModeSettings;
+import lineageos.profiles.StreamSettings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+public class ProfileTest extends AndroidTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Only run this if we support profiles service
+ org.junit.Assume.assumeTrue(mContext.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.PROFILES));
+ }
+
+ @MediumTest
+ public void testProfileConnectionSettingsUnravelFromParcel() {
+ Profile profile = new Profile("Connection Profile");
+ ConnectionSettings expectedConnectionSettings =
+ new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_GPS,
+ ConnectionSettings.BooleanState.STATE_DISALED, true);
+ profile.setConnectionSettings(expectedConnectionSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+ ConnectionSettings actualConnectionSettings = fromParcel.getSettingsForConnection(
+ expectedConnectionSettings.getConnectionId());
+
+ assertEquals(expectedConnectionSettings.getConnectionId(),
+ actualConnectionSettings.getConnectionId());
+ assertEquals(expectedConnectionSettings.getValue(),
+ actualConnectionSettings.getValue());
+ assertEquals(expectedConnectionSettings.isDirty(),
+ actualConnectionSettings.isDirty());
+ assertEquals(expectedConnectionSettings.isOverride(),
+ actualConnectionSettings.isOverride());
+ }
+
+ @MediumTest
+ public void testProfileAirplaneModeSettingsUnravelFromParcel() {
+ Profile profile = new Profile("AirplaneMode Profile");
+ AirplaneModeSettings expectedAirplaneModeSettings =
+ new AirplaneModeSettings(AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ profile.setAirplaneMode(expectedAirplaneModeSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+ AirplaneModeSettings actualAirplaneModeSettings = fromParcel.getAirplaneMode();
+
+ assertEquals(expectedAirplaneModeSettings.getValue(),
+ actualAirplaneModeSettings.getValue());
+ assertEquals(expectedAirplaneModeSettings.isDirty(),
+ actualAirplaneModeSettings.isDirty());
+ assertEquals(expectedAirplaneModeSettings.isOverride(),
+ expectedAirplaneModeSettings.isOverride());
+ }
+
+ @MediumTest
+ public void testProfileBrightnessSettingsUnravelFromParcel() {
+ Profile profile = new Profile("Brightness Profile");
+ BrightnessSettings expectedBrightnessSettings = new BrightnessSettings(0, true);
+ profile.setBrightness(expectedBrightnessSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+ BrightnessSettings actualBrightnessSettings = fromParcel.getBrightness();
+
+ assertEquals(expectedBrightnessSettings.getValue(), actualBrightnessSettings.getValue());
+ assertEquals(expectedBrightnessSettings.isOverride(),
+ actualBrightnessSettings.isOverride());
+ assertEquals(expectedBrightnessSettings.isDirty(), actualBrightnessSettings.isDirty());
+ }
+
+ @MediumTest
+ public void testProfileRingmodeSettingsUnravelFromParcel() {
+ Profile profile = new Profile("Ringmode Profile");
+ RingModeSettings expectedRingModeSettings =
+ new RingModeSettings(RingModeSettings.RING_MODE_MUTE, true);
+ profile.setRingMode(expectedRingModeSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ RingModeSettings actualRingModeSettings = fromParcel.getRingMode();
+
+ assertNotNull(fromParcel);
+ assertEquals(expectedRingModeSettings.getValue(), actualRingModeSettings.getValue());
+ assertEquals(expectedRingModeSettings.isDirty(), actualRingModeSettings.isDirty());
+ assertEquals(expectedRingModeSettings.isOverride(), actualRingModeSettings.isOverride());
+ }
+
+ @MediumTest
+ public void testProfileStreamSettingsUnravelFromParcel() {
+ Profile profile = new Profile("Stream Profile");
+ StreamSettings expectedStreamSettings =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ profile.setStreamSettings(expectedStreamSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ StreamSettings actualStreamSettings = fromParcel.getSettingsForStream(
+ expectedStreamSettings.getStreamId());
+
+ assertNotNull(fromParcel);
+ assertEquals(expectedStreamSettings.getValue(), actualStreamSettings.getValue());
+ assertEquals(expectedStreamSettings.isOverride(), actualStreamSettings.isOverride());
+ assertEquals(expectedStreamSettings.isDirty(), actualStreamSettings.isDirty());
+ }
+
+ @MediumTest
+ public void testProfileLockSettingsUnravelFromParcel() {
+ Profile profile = new Profile("Lock Profile");
+ LockSettings expectedLockSettings = new LockSettings(Profile.LockMode.INSECURE);
+ profile.setScreenLockMode(expectedLockSettings);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ LockSettings actualLockSettings = fromParcel.getScreenLockMode();
+
+ assertNotNull(fromParcel);
+ assertEquals(expectedLockSettings.getValue(), actualLockSettings.getValue());
+ assertEquals(expectedLockSettings.isDirty(), actualLockSettings.isDirty());
+ }
+
+ @MediumTest
+ public void testProfileUnravelFromParcel() {
+ Profile profile = new Profile("Single Profile");
+ profile.setProfileType(Profile.Type.TOGGLE);
+ profile.setDozeMode(Profile.DozeMode.ENABLE);
+ profile.setStatusBarIndicator(true);
+
+ // Write to parcel
+ Parcel parcel = Parcel.obtain();
+ profile.writeToParcel(parcel, 0);
+
+ // Rewind
+ parcel.setDataPosition(0);
+
+ // Verify data when unraveling
+ Profile fromParcel = Profile.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+ assertEquals(profile.getName(), fromParcel.getName());
+ assertEquals(profile.getProfileType(), fromParcel.getProfileType());
+ assertEquals(profile.getDozeMode(), fromParcel.getDozeMode());
+ assertEquals(profile.getStatusBarIndicator(), fromParcel.getStatusBarIndicator());
+ }
+
+ private static final int EXPECTED_PROFILE_TRIGGER_TYPE = Profile.TriggerType.WIFI;
+ private static final String EXPECTED_PROFILE_TRIGGER_ID = "1337";
+ private static final int EXPECTED_PROFILE_TRIGGER_STATE = Profile.TriggerState.ON_CONNECT;
+ private static final String EXPECTED_PROFILE_TRIGGER_NAME = "ON_CONNECT_WIFI_TRIGGER";
+ private Profile.ProfileTrigger createSampleProfileTrigger() {
+ return new Profile.ProfileTrigger(EXPECTED_PROFILE_TRIGGER_TYPE,
+ EXPECTED_PROFILE_TRIGGER_ID, EXPECTED_PROFILE_TRIGGER_STATE,
+ EXPECTED_PROFILE_TRIGGER_NAME);
+ }
+
+ @SmallTest
+ public void testProfileTriggerId() {
+ Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger();
+ assertEquals(EXPECTED_PROFILE_TRIGGER_ID, profileTrigger.getId());
+ }
+
+ @SmallTest
+ public void testProfileTriggerName() {
+ Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger();
+ assertEquals(EXPECTED_PROFILE_TRIGGER_NAME, profileTrigger.getName());
+ }
+
+ @SmallTest
+ public void testProfileTriggerState() {
+ Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger();
+ assertEquals(EXPECTED_PROFILE_TRIGGER_STATE, profileTrigger.getState());
+ }
+
+ @SmallTest
+ public void testProfileTriggerType() {
+ Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger();
+ assertEquals(EXPECTED_PROFILE_TRIGGER_STATE, profileTrigger.getType());
+ }
+
+ @SmallTest
+ public void testProfileConstructor() {
+ String expectedName = "PROFILE_NAME";
+ Profile profile = new Profile(expectedName);
+ assertEquals(expectedName, profile.getName());
+ }
+
+ @SmallTest
+ public void testProfileAddSecondaryUuid() {
+ UUID[] expectedUUIDs = new UUID[2];
+ UUID expectedUUID1 = UUID.randomUUID();
+ UUID expectedUUID2 = UUID.randomUUID();
+ expectedUUIDs[0] = expectedUUID1;
+ expectedUUIDs[1] = expectedUUID2;
+
+ Profile profile = new Profile("Single Profile");
+ profile.addSecondaryUuid(expectedUUID1);
+ profile.addSecondaryUuid(expectedUUID2);
+
+ UUID[] actualUUIDs = profile.getSecondaryUuids();
+ for (int i = 0; i < actualUUIDs.length; i++) {
+ assertEquals(actualUUIDs[i], expectedUUIDs[i]);
+ }
+
+ profile.setSecondaryUuids(Arrays.asList(expectedUUIDs));
+ for (int i = 0; i < actualUUIDs.length; i++) {
+ assertEquals(actualUUIDs[i], expectedUUIDs[i]);
+ }
+ }
+
+ @SmallTest
+ public void testProfileGetAirplaneMode() {
+ Profile profile = new Profile("AirplaneMode Profile");
+ AirplaneModeSettings expectedAirplaneModeSettings =
+ new AirplaneModeSettings(AirplaneModeSettings.BooleanState.STATE_ENABLED, true);
+ profile.setAirplaneMode(expectedAirplaneModeSettings);
+
+ AirplaneModeSettings actualAirplaneModeSettings = profile.getAirplaneMode();
+ assertEquals(expectedAirplaneModeSettings.getValue(),
+ actualAirplaneModeSettings.getValue());
+ assertEquals(expectedAirplaneModeSettings.isOverride(),
+ actualAirplaneModeSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testProfileGetBrightness() {
+ Profile profile = new Profile("Brightness Profile");
+ BrightnessSettings expectedBrightnessSettings = new BrightnessSettings(0, true);
+ profile.setBrightness(expectedBrightnessSettings);
+
+ BrightnessSettings actualBrightnessSettings = profile.getBrightness();
+ assertEquals(expectedBrightnessSettings.getValue(), actualBrightnessSettings.getValue());
+ assertEquals(expectedBrightnessSettings.isOverride(), actualBrightnessSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testProfileGetConnectionSettingsWithSubId() {
+ int targetSubId = 0;
+ Profile profile = new Profile("Connection Sub Id Profile");
+ ConnectionSettings expectedConnectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_2G3G4G,
+ ConnectionSettings.BooleanState.STATE_ENABLED, true);
+ expectedConnectionSettings.setSubId(targetSubId);
+ profile.setConnectionSettings(expectedConnectionSettings);
+
+ ConnectionSettings actualConnectionSettings =
+ profile.getConnectionSettingWithSubId(targetSubId);
+ assertEquals(expectedConnectionSettings.getConnectionId(),
+ actualConnectionSettings.getConnectionId());
+ assertEquals(expectedConnectionSettings.getValue(), actualConnectionSettings.getValue());
+ assertEquals(expectedConnectionSettings.isOverride(),
+ actualConnectionSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testProfileGetConnectionSettings() {
+ Profile profile = new Profile("Connection Profile");
+
+ ConnectionSettings expectedConnectionSettings1 = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_2G3G4G,
+ ConnectionSettings.BooleanState.STATE_ENABLED, true);
+ profile.setConnectionSettings(expectedConnectionSettings1);
+ ConnectionSettings expectedConnectionSettings2 = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH,
+ ConnectionSettings.BooleanState.STATE_DISALED, false);
+ profile.setConnectionSettings(expectedConnectionSettings2);
+
+ List<ConnectionSettings> expectedConnectionSettings = new ArrayList<>();
+ // inverted because the backing structure does it this way :/
+ expectedConnectionSettings.add(expectedConnectionSettings2);
+ expectedConnectionSettings.add(expectedConnectionSettings1);
+
+ List<ConnectionSettings> actualConnectionSettings = new ArrayList<>(
+ profile.getConnectionSettings());
+ for (int i = 0; i < actualConnectionSettings.size(); i++) {
+ ConnectionSettings expectedConnectionSetting = expectedConnectionSettings.get(i);
+ ConnectionSettings actualConnectionSetting = actualConnectionSettings.get(i);
+ assertEquals(expectedConnectionSetting.getConnectionId(),
+ actualConnectionSetting.getConnectionId());
+ assertEquals(expectedConnectionSetting.getValue(), actualConnectionSetting.getValue());
+ assertEquals(expectedConnectionSetting.isOverride(),
+ actualConnectionSetting.isOverride());
+ }
+ }
+
+ @SmallTest
+ public void testProfileGetDozeMode() {
+ int expectedDozeMode = Profile.DozeMode.ENABLE;
+ Profile profile = new Profile("Doze Mode Profile");
+ profile.setDozeMode(expectedDozeMode);
+ assertEquals(expectedDozeMode, profile.getDozeMode());
+ }
+
+ @SmallTest
+ public void testProfileGetExpandedDesktopMode() {
+ int expectedExpandedDesktopMode = Profile.ExpandedDesktopMode.ENABLE;
+ Profile profile = new Profile("Desktop Mode Profile");
+ profile.setExpandedDesktopMode(expectedExpandedDesktopMode);
+ assertEquals(expectedExpandedDesktopMode, profile.getExpandedDesktopMode());
+ }
+
+ @SmallTest
+ public void testProfileGetNotificationLightMode() {
+ int expectedNotificationLightMode = Profile.NotificationLightMode.ENABLE;
+ Profile profile = new Profile("Notification Light Mode Profile");
+ profile.setNotificationLightMode(expectedNotificationLightMode);
+ assertEquals(expectedNotificationLightMode, profile.getNotificationLightMode());
+ }
+
+ @SmallTest
+ public void testProfileGetProfileType() {
+ int expectedProfileType = Profile.Type.CONDITIONAL;
+ Profile profile = new Profile("Profile Type Profile");
+ profile.setProfileType(expectedProfileType);
+ assertEquals(expectedProfileType, profile.getProfileType());
+ }
+
+ @SmallTest
+ public void testProfileGetRingMode() {
+ Profile profile = new Profile("Ringmode Profile");
+ RingModeSettings expectedRingModeSettings =
+ new RingModeSettings(RingModeSettings.RING_MODE_MUTE, true);
+ profile.setRingMode(expectedRingModeSettings);
+
+ RingModeSettings actualRingModeSettings = profile.getRingMode();
+ assertEquals(expectedRingModeSettings.getValue(), actualRingModeSettings.getValue());
+ assertEquals(expectedRingModeSettings.isDirty(), actualRingModeSettings.isDirty());
+ assertEquals(expectedRingModeSettings.isOverride(), actualRingModeSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testProfileGetLockScreenMode() {
+ Profile profile = new Profile("Lock Profile");
+ LockSettings expectedLockSettings = new LockSettings(Profile.LockMode.INSECURE);
+ profile.setScreenLockMode(expectedLockSettings);
+
+ LockSettings actualLockSettings = profile.getScreenLockMode();
+ assertEquals(expectedLockSettings.getValue(), actualLockSettings.getValue());
+ assertEquals(expectedLockSettings.isDirty(), actualLockSettings.isDirty());
+ }
+
+ @SmallTest
+ public void testProfileGetSettingForConnection() {
+ Profile profile = new Profile("Connection Profile");
+ ConnectionSettings expectedConnectionSettings = new ConnectionSettings(
+ ConnectionSettings.PROFILE_CONNECTION_2G3G4G,
+ ConnectionSettings.BooleanState.STATE_ENABLED, true);
+ profile.setConnectionSettings(expectedConnectionSettings);
+
+ ConnectionSettings actualConnectionSettings =
+ profile.getSettingsForConnection(ConnectionSettings.PROFILE_CONNECTION_2G3G4G);
+ assertEquals(expectedConnectionSettings.getConnectionId(),
+ actualConnectionSettings.getConnectionId());
+ assertEquals(expectedConnectionSettings.getValue(), actualConnectionSettings.getValue());
+ assertEquals(expectedConnectionSettings.isOverride(),
+ actualConnectionSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testProfileGetSettingForStream() {
+ Profile profile = new Profile("Stream Profile");
+ StreamSettings expectedStreamSettings =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ profile.setStreamSettings(expectedStreamSettings);
+
+ StreamSettings actualStreamSettings = profile.getSettingsForStream(
+ expectedStreamSettings.getStreamId());
+
+ assertEquals(expectedStreamSettings.getValue(), actualStreamSettings.getValue());
+ assertEquals(expectedStreamSettings.isOverride(), actualStreamSettings.isOverride());
+ assertEquals(expectedStreamSettings.isDirty(), actualStreamSettings.isDirty());
+ }
+
+ @SmallTest
+ public void testProfileGetStreamSettings() {
+ Profile profile = new Profile("Stream Profile");
+ StreamSettings expectedStreamSettings1 =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ profile.setStreamSettings(expectedStreamSettings1);
+ StreamSettings expectedStreamSettings2 =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ profile.setStreamSettings(expectedStreamSettings2);
+
+ List<StreamSettings> expectedStreamSettings = new ArrayList<>();
+ expectedStreamSettings.add(expectedStreamSettings1);
+ expectedStreamSettings.add(expectedStreamSettings2);
+
+ List<StreamSettings> actualStreamSettings = new ArrayList<>(
+ profile.getStreamSettings());
+
+ for (int i = 0; i < actualStreamSettings.size(); i++) {
+ StreamSettings expectedStreamSetting = actualStreamSettings.get(i);
+ StreamSettings actualStreamSetting = actualStreamSettings.get(i);
+ assertEquals(expectedStreamSetting.getStreamId(),
+ actualStreamSetting.getStreamId());
+ assertEquals(expectedStreamSetting.getValue(), actualStreamSetting.getValue());
+ assertEquals(expectedStreamSetting.isOverride(),
+ actualStreamSetting.isOverride());
+ }
+ }
+
+ @SmallTest
+ public void testProfileGetTriggerState() {
+ Profile profile = new Profile("ProfileTrigger Profile");
+ Profile.ProfileTrigger profileTrigger = createSampleProfileTrigger();
+ profile.setTrigger(profileTrigger);
+ assertEquals(EXPECTED_PROFILE_TRIGGER_STATE,
+ profile.getTriggerState(EXPECTED_PROFILE_TRIGGER_TYPE,
+ EXPECTED_PROFILE_TRIGGER_ID));
+ }
+
+ @SmallTest
+ public void testProfileGetTriggersFromType() {
+ Profile profile = new Profile("ProfileTrigger Profile");
+ Profile.ProfileTrigger profileTrigger1 = createSampleProfileTrigger();
+ Profile.ProfileTrigger profileTrigger2 = createSampleProfileTrigger();
+ profile.setTrigger(profileTrigger1);
+ profile.setTrigger(profileTrigger2);
+
+ List<Profile.ProfileTrigger> expectedProfileTriggers = new ArrayList<>();
+ expectedProfileTriggers.add(profileTrigger1);
+ expectedProfileTriggers.add(profileTrigger2);
+
+ List<Profile.ProfileTrigger> actualProfileTriggers = new ArrayList<>(
+ profile.getTriggersFromType(EXPECTED_PROFILE_TRIGGER_TYPE));
+
+ for (int i = 0; i < actualProfileTriggers.size(); i++) {
+ Profile.ProfileTrigger expectedProfileTrigger = expectedProfileTriggers.get(i);
+ Profile.ProfileTrigger actualProfileTrigger = expectedProfileTriggers.get(i);
+ assertEquals(expectedProfileTrigger.getId(), actualProfileTrigger.getId());
+ assertEquals(expectedProfileTrigger.getName(), actualProfileTrigger.getName());
+ assertEquals(expectedProfileTrigger.getState(), actualProfileTrigger.getState());
+ assertEquals(expectedProfileTrigger.getType(), actualProfileTrigger.getType());
+ }
+ }
+
+ @SmallTest
+ public void testProfileIsConditionalType() {
+ Profile profile = new Profile("Mutable Profile");
+ profile.setProfileType(Profile.Type.TOGGLE);
+ assertFalse(profile.isConditionalType());
+ profile.setProfileType(Profile.Type.CONDITIONAL);
+ assertTrue(profile.isConditionalType());
+ }
+
+ @SmallTest
+ public void testProfileSetName() {
+ String expectedProfileName = "MUTABLE Profile";
+ Profile profile = new Profile("Mutable Profile");
+ profile.setName(expectedProfileName);
+ assertEquals(expectedProfileName, profile.getName());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java
new file mode 100644
index 00000000..4c1bfd6e
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/RingModeSettingsTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.profiles.RingModeSettings;
+
+public class RingModeSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructWholly() {
+ RingModeSettings ringSettings = new RingModeSettings(
+ RingModeSettings.RING_MODE_MUTE, true);
+ assertEquals(RingModeSettings.RING_MODE_MUTE, ringSettings.getValue());
+ assertEquals(true, ringSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyOverride() {
+ RingModeSettings ringSettings = new RingModeSettings(
+ RingModeSettings.RING_MODE_MUTE, true);
+ ringSettings.setOverride(false);
+ assertEquals(false, ringSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ String expectedValue = RingModeSettings.RING_MODE_NORMAL;
+ RingModeSettings ringSettings = new RingModeSettings(
+ RingModeSettings.RING_MODE_MUTE, true);
+ ringSettings.setValue(expectedValue);
+ assertEquals(expectedValue, ringSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java b/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java
new file mode 100644
index 00000000..783d293e
--- /dev/null
+++ b/tests/src/org/lineageos/tests/profiles/unit/StreamSettingsTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.lineageos.tests.profiles.unit;
+
+import android.media.AudioManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.profiles.StreamSettings;
+
+public class StreamSettingsTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testConstructManually() {
+ StreamSettings streamSettings =
+ new StreamSettings(AudioManager.STREAM_RING);
+ assertEquals(AudioManager.STREAM_RING, streamSettings.getStreamId());
+ }
+
+ @SmallTest
+ public void testConstructWholly() {
+ StreamSettings streamSettings =
+ new StreamSettings(AudioManager.STREAM_RING, 0, true);
+ assertEquals(AudioManager.STREAM_RING, streamSettings.getStreamId());
+ assertEquals(0, streamSettings.getValue());
+ assertEquals(true, streamSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyOverride() {
+ StreamSettings streamSettings =
+ new StreamSettings(AudioManager.STREAM_RING);
+ streamSettings.setOverride(true);
+ assertEquals(true, streamSettings.isOverride());
+ }
+
+ @SmallTest
+ public void testVerifyValue() {
+ int expectedValue = AudioManager.STREAM_ALARM;
+ StreamSettings streamSettings =
+ new StreamSettings(AudioManager.STREAM_RING);
+ streamSettings.setValue(expectedValue);
+ assertEquals(expectedValue, streamSettings.getValue());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java b/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java
new file mode 100644
index 00000000..d6f61e80
--- /dev/null
+++ b/tests/src/org/lineageos/tests/providers/LineageSettingsTest.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.providers;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import lineageos.providers.LineageSettings;
+
+public class LineageSettingsTest extends AndroidTestCase{
+ private ContentResolver mContentResolver;
+ private LineageSettingsTestObserver mTestObserver;
+
+ private static boolean sIsOnChangedCalled = false;
+ private static Uri sExpectedUriChange = null;
+
+ @Override
+ public void setUp() {
+ mContentResolver = getContext().getContentResolver();
+ mTestObserver = new LineageSettingsTestObserver(null);
+ }
+
+ @Override
+ public void tearDown() {
+ mContentResolver.unregisterContentObserver(mTestObserver);
+ }
+
+ @MediumTest
+ public void testPutAndGetSystemString() {
+ final String key = LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER;
+
+ // put
+ final String expectedValue = "1";
+ boolean isPutSuccessful = LineageSettings.System.putString(mContentResolver, key, expectedValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ String actualValue = LineageSettings.System.getString(mContentResolver, key);
+ assertEquals(expectedValue, actualValue);
+
+ // setup observer
+ sIsOnChangedCalled = false;
+ sExpectedUriChange = LineageSettings.System.getUriFor(key);
+ mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver,
+ UserHandle.USER_ALL);
+
+ // replace
+ final String expectedReplaceValue = "0";
+ isPutSuccessful = LineageSettings.System.putString(mContentResolver, key, expectedReplaceValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ actualValue = LineageSettings.System.getString(mContentResolver, key);
+ assertEquals(expectedReplaceValue, actualValue);
+
+ // delete to clean up
+ int rowsAffected = mContentResolver.delete(LineageSettings.System.CONTENT_URI,
+ Settings.NameValueTable.NAME + " = ?", new String[]{ key });
+ assertEquals(1, rowsAffected);
+
+ if (!sIsOnChangedCalled) {
+ fail("On change was never called or was called with the wrong uri");
+ }
+ }
+
+ @MediumTest
+ public void testPutAndGetSecureString() {
+ /* TODO: FIXME
+ final String key = LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER;
+
+ // put
+ final String expectedValue = "0";
+ boolean isPutSuccessful = LineageSettings.Secure.putString(mContentResolver, key, expectedValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ String actualValue = LineageSettings.Secure.getString(mContentResolver, key);
+ assertEquals(expectedValue, actualValue);
+
+ // setup observer
+ sIsOnChangedCalled = false;
+ sExpectedUriChange = LineageSettings.Secure.getUriFor(key);
+ mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver,
+ UserHandle.USER_ALL);
+
+ // replace
+ final String expectedReplaceValue = "1";
+ isPutSuccessful = LineageSettings.Secure.putString(mContentResolver, key, expectedReplaceValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ actualValue = LineageSettings.Secure.getString(mContentResolver, key);
+ assertEquals(expectedReplaceValue, actualValue);
+
+ // delete to clean up
+ int rowsAffected = mContentResolver.delete(LineageSettings.Secure.CONTENT_URI,
+ Settings.NameValueTable.NAME + " = ?", new String[]{ key });
+ assertEquals(1, rowsAffected);
+
+ if (!sIsOnChangedCalled) {
+ fail("On change was never called or was called with the wrong uri");
+ } */
+ }
+
+ @MediumTest
+ public void testPutAndGetGlobalString() {
+ final String key = "key";
+
+ // put
+ final String expectedValue = "globalTestValue1";
+ boolean isPutSuccessful = LineageSettings.Global.putString(mContentResolver, key, expectedValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ String actualValue = LineageSettings.Global.getString(mContentResolver, key);
+ assertEquals(expectedValue, actualValue);
+
+ // setup observer
+ sIsOnChangedCalled = false;
+ sExpectedUriChange = LineageSettings.Global.getUriFor(key);
+ mContentResolver.registerContentObserver(sExpectedUriChange, false, mTestObserver,
+ UserHandle.USER_OWNER);
+
+ // replace
+ final String expectedReplaceValue = "globalTestValue2";
+ isPutSuccessful = LineageSettings.Global.putString(mContentResolver, key, expectedReplaceValue);
+ assertTrue(isPutSuccessful);
+
+ // get
+ actualValue = LineageSettings.Global.getString(mContentResolver, key);
+ assertEquals(expectedReplaceValue, actualValue);
+
+ // delete to clean up
+ int rowsAffected = mContentResolver.delete(LineageSettings.Global.CONTENT_URI,
+ Settings.NameValueTable.NAME + " = ?", new String[]{ key });
+ assertEquals(1, rowsAffected);
+
+ if (!sIsOnChangedCalled) {
+ fail("On change was never called or was called with the wrong uri");
+ }
+ }
+
+ private class LineageSettingsTestObserver extends ContentObserver {
+
+ public LineageSettingsTestObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (sExpectedUriChange.equals(uri)) {
+ sIsOnChangedCalled = true;
+ }
+ }
+ }
+
+ // TODO Add tests for other users
+}
diff --git a/tests/src/org/lineageos/tests/util/ColorUtilTest.java b/tests/src/org/lineageos/tests/util/ColorUtilTest.java
new file mode 100644
index 00000000..9ce91f96
--- /dev/null
+++ b/tests/src/org/lineageos/tests/util/ColorUtilTest.java
@@ -0,0 +1,123 @@
+/**
+ * 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.lineageos.tests.util;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.test.AndroidTestCase;
+import lineageos.util.ColorUtils;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class ColorUtilTest extends AndroidTestCase {
+ private ColorUtils mColorUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mColorUtils = new ColorUtils();
+ }
+
+ public void testDropAlpha() {
+ // With pre-existing alpha
+ int color = 0xBBCCDD;
+ int alpha = 0xAA000000;
+ int result = mColorUtils.dropAlpha(color | alpha);
+ // Assert alpha was removed
+ assertEquals(Color.alpha(result), 0);
+ // Ensure color is preserved
+ assertEquals(result & color, color);
+
+ // Without pre-existing alpha
+ color = Color.argb(0, 100, 200 ,300);
+ result = mColorUtils.dropAlpha(color);
+ // Assert alpha was removed
+ assertEquals(Color.alpha(result), 0);
+ // Ensure color is preserved
+ assertEquals(result, color);
+ }
+
+ public void testGenerateAlertColorFromDrawable() {
+ // Test null drawable
+ int color = mColorUtils.generateAlertColorFromDrawable(null);
+ assertEquals(color, Color.BLACK);
+
+ Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
+ bitmapDrawable.setBounds(0, 0, 10, 10);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawColor(Color.RED);
+
+ // Test fully red bitmap
+ color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable);
+ assertEquals(color, Color.RED);
+ color = mColorUtils.generateAlertColorFromDrawable(
+ getColorDrawableFromBitmapDrawable(bitmapDrawable));
+ assertEquals(color, Color.RED);
+
+ // Test blue/red bitmap with blue dominating
+ Paint p = new Paint();
+ p.setColor(Color.BLUE);
+ p.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawRect(0, 0, 8, 8, p);
+ color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable);
+ assertEquals(color, Color.BLUE);
+ color = mColorUtils.generateAlertColorFromDrawable(
+ getColorDrawableFromBitmapDrawable(bitmapDrawable));
+ assertEquals(color, Color.BLUE);
+
+ // Test large white + small blue scenario
+ canvas.drawColor(Color.WHITE);
+ canvas.drawRect(0, 0, 2, 2, p);
+ color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable);
+ assertEquals(color, Color.BLUE);
+ color = mColorUtils.generateAlertColorFromDrawable(
+ getColorDrawableFromBitmapDrawable(bitmapDrawable));
+ assertEquals(color, Color.BLUE);
+
+ // Test large white + small black scenario
+ canvas.drawColor(Color.WHITE);
+ p.setColor(Color.BLACK);
+ canvas.drawRect(0, 0, 2, 2, p);
+ color = mColorUtils.generateAlertColorFromDrawable(bitmapDrawable);
+ assertEquals(color, Color.WHITE);
+ color = mColorUtils.generateAlertColorFromDrawable(
+ getColorDrawableFromBitmapDrawable(bitmapDrawable));
+ assertEquals(color, Color.WHITE);
+
+ assertEquals(bitmap.isRecycled(), false);
+ bitmap.recycle();
+ }
+
+ private ColorDrawable getColorDrawableFromBitmapDrawable(final BitmapDrawable bitmapDrawable) {
+ ColorDrawable colorDrawable = Mockito.mock(ColorDrawable.class);
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Canvas canvas = (Canvas) invocation.getArguments()[0];
+ bitmapDrawable.draw(canvas);
+ return null;
+ }
+ }).when(colorDrawable).draw(Mockito.any(Canvas.class));
+ return colorDrawable;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/VersioningTest.java b/tests/src/org/lineageos/tests/versioning/VersioningTest.java
new file mode 100644
index 00000000..9cbf2752
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/VersioningTest.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.versioning;
+
+import android.widget.Toast;
+import lineageos.os.Build;
+
+import org.lineageos.tests.TestActivity;
+
+public class VersioningTest extends TestActivity {
+ @Override
+ protected String tag() {
+ return null;
+ }
+
+ @Override
+ protected Test[] tests() {
+ return mTests;
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("test retrieve version") {
+ public void run() {
+ Toast.makeText(VersioningTest.this,
+ "Current API version is " + Build.LINEAGE_VERSION.SDK_INT + " which is "
+ + Build.getNameForSDKInt(Build.LINEAGE_VERSION.SDK_INT),
+ Toast.LENGTH_SHORT).show();
+ }
+ },
+ new Test("test target version larger") {
+ public void run() {
+ int currentapiVersion = Build.LINEAGE_VERSION.SDK_INT;
+ if (currentapiVersion >= Build.LINEAGE_VERSION_CODES.APRICOT){
+ Toast.makeText(VersioningTest.this,
+ "Current API version is greater or equal to "
+ + Build.getNameForSDKInt(Build.LINEAGE_VERSION_CODES.APRICOT),
+ Toast.LENGTH_LONG).show();
+ } else{
+ Toast.makeText(VersioningTest.this,
+ "Current API version is below target SKD version "
+ + Build.LINEAGE_VERSION_CODES.APRICOT,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+ };
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java b/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java
new file mode 100644
index 00000000..47032bd1
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/BinderTransactionTest.java
@@ -0,0 +1,206 @@
+/**
+ * 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.lineageos.tests.versioning.unit;
+
+import android.content.Context;
+import android.os.Binder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.Pair;
+import org.lineageos.tests.LineageOSTestApplication;
+import org.lineageos.tests.versioning.unit.apiv2.ApiV2PriorReleaseInterfaces;
+import org.lineageos.tests.versioning.unit.apiv4.ApiV4PriorReleaseInterfaces;
+import org.lineageos.tests.versioning.unit.apiv5.ApiV5PriorReleaseInterfaces;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.runner.AndroidJUnitRunner;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * These tests validate the enumerated binder transaction call ids per each
+ * release api level against the current framework.
+ *
+ * This is to validate that no interface contracts are broken in terms of binder
+ * call method mapping between releases.
+ *
+ * After too much searching on the internet, I found that no one was bored enough to
+ * spend time on this awesomely boring concept. But I am.
+ *
+ * Also this is a fun endeavour into parameterized unit testing, and by fun, I mean
+ * horrible and full of drinking.
+ *
+ * If you need to blame anyone for this concept, look no further than danesh@cyngn.com
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class BinderTransactionTest extends AndroidTestCase {
+ private static final String TAG = BinderTransactionTest.class.getSimpleName();
+ private static final String STUB_SUFFIX = "$Stub";
+ private static final String LINEAGEOS_NAMESPACE = "lineageos";
+ private static final String TRANSACTION_PREFIX = "TRANSACTION_";
+
+ private static final int NOT_FROM_PRIOR_RELEASE = -1;
+
+ private String mField;
+ private int mExpectedValue;
+ private int mActualValue;
+ private static Context sContext;
+
+ private static ArrayList<String> mKnownSdkClasses;
+ private static Map<String, Map<String, Integer>> mApiMethodsAndValues =
+ new HashMap<String, Map<String, Integer>>();
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Test
+ public void testClassLoaderGivesSDKClasses() {
+ /**
+ * Verify we can retrieve our sdk classes from this package
+ */
+ assertNotNull(mKnownSdkClasses);
+ assertTrue(mKnownSdkClasses.size() > 0);
+ }
+
+ private static void doSetup() {
+ mKnownSdkClasses = MagicalDexHelper.getLoadedClasses(
+ LineageOSTestApplication.getStaticApplicationContext(), LINEAGEOS_NAMESPACE);
+ sContext = LineageOSTestApplication.getStaticApplicationContext();
+ addInterfaces(ApiV2PriorReleaseInterfaces.getInterfaces());
+ addInterfaces(ApiV4PriorReleaseInterfaces.getInterfaces());
+ addInterfaces(ApiV5PriorReleaseInterfaces.getInterfaces());
+ }
+
+ private static void addInterfaces(Map<String, Map<String, Integer>> mapToAdd) {
+ for (String key : mapToAdd.keySet()) {
+ if (mApiMethodsAndValues.get(key) != null) {
+ Map<String, Integer> internalMap = mApiMethodsAndValues.get(key);
+ internalMap.putAll(mapToAdd.get(key));
+ } else {
+ Map<String, Integer> internalMap = mapToAdd.get(key);
+ mApiMethodsAndValues.put(key, internalMap);
+ }
+ }
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> data() {
+ doSetup();
+ //Ughhh, lets pretend this never happened
+ ArrayList<Pair<String, String>> targetClassAndFields =
+ new ArrayList<Pair<String, String>>();
+ ArrayList<Integer> actualValues = new ArrayList<Integer>();
+
+ for (String sClazz : mKnownSdkClasses) {
+ if (sClazz.endsWith(STUB_SUFFIX)) {
+ try {
+ Class clazz = MagicalDexHelper.loadClassForNameSpace(LineageOSTestApplication
+ .getStaticApplicationContext(), sClazz);
+ Field[] fields = clazz.getDeclaredFields();
+ Pattern pattern = Pattern.compile("\\.([\\w]+)\\$");
+ Matcher matcher = pattern.matcher(clazz.getName());
+ String className = null;
+ if (matcher.find()) {
+ className = matcher.group(1).substring(0, matcher.group(1).length());
+ }
+
+ for (Field field : fields) {
+ if (field.getName().startsWith(TRANSACTION_PREFIX)) {
+ field.setAccessible(true);
+ String fieldName = field.getName().substring(
+ TRANSACTION_PREFIX.length());
+ fieldName = fieldName.split("_")[0];
+ Pair<String, String> classAndField = new Pair<String, String>(
+ className, fieldName);
+ Log.d(TAG, "Adding: " + classAndField.first + " with field "
+ + classAndField.second);
+ targetClassAndFields.add(classAndField);
+ try {
+ actualValues.add(field.getInt(clazz));
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Unable to access " + field.getName());
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new AssertionError("Unable to load class " + sClazz);
+ }
+ }
+ }
+ Object[][] values = new Object[targetClassAndFields.size()][3];
+
+ for (int i = 0; i < targetClassAndFields.size(); i++) {
+ Pair<String, String> targetClassAndField = targetClassAndFields.get(i);
+ values[i][0] = targetClassAndField.second;
+ values[i][1] = lookupValueForField(targetClassAndField.first,
+ targetClassAndField.second);
+ values[i][2] = actualValues.get(i);
+ }
+ return Arrays.asList(values);
+ }
+
+ //Look up the target fields value from a prior release
+ private static Object lookupValueForField(String clazz, String fieldName) {
+ Log.d(TAG, "Looking up: " + clazz + " with field "
+ + fieldName);
+ Map<String, Integer> internalMap = mApiMethodsAndValues.get(clazz);
+ if (internalMap == null || !internalMap.containsKey(fieldName)) {
+ Log.d(TAG, "Internal map for " + clazz + " is null or doesn't contain entry");
+ return NOT_FROM_PRIOR_RELEASE;
+ }
+ return internalMap.get(fieldName);
+ }
+
+ public BinderTransactionTest(String targetField, Integer expectedValue, Integer actualValue) {
+ mField = targetField;
+ mExpectedValue = expectedValue;
+ mActualValue = actualValue;
+ }
+
+ @Test
+ public void testBinderTransactionValidation() {
+ Log.d(TAG, "Testing: " + mField + " with expected value of " + mExpectedValue
+ + " and actual value of " + mActualValue);
+ if (mExpectedValue == NOT_FROM_PRIOR_RELEASE) {
+ //This is a new interface, no need to test against
+ return;
+ }
+ try {
+ assertEquals(mExpectedValue, mActualValue);
+ } catch (AssertionError e) {
+ throw new AssertionError("For the field " + mField + " expected value "
+ + mExpectedValue + " but got " + mActualValue);
+ }
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java b/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java
new file mode 100644
index 00000000..02bdf9a9
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/BuildTest.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.versioning.unit;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.os.Build;
+
+import android.test.AndroidTestCase;
+import lineageos.os.Concierge;
+
+/**
+ * Created by adnan on 7/14/15.
+ */
+public class BuildTest extends AndroidTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @SmallTest
+ public void testFetchSdkApiLevelExists() {
+ assertNotNull(Build.LINEAGE_VERSION.SDK_INT);
+ }
+
+ @SmallTest
+ public void testSdkApiLevelCurrent() {
+ assertEquals(Concierge.PARCELABLE_VERSION, Build.LINEAGE_VERSION.SDK_INT);
+ }
+
+ @SmallTest
+ public void testSdkApiLevelCanMatch() {
+ String apiName = Build.getNameForSDKInt(Build.LINEAGE_VERSION.SDK_INT);
+ assertNotNull(apiName);
+ assertEquals(Build.getNameForSDKInt(Concierge.PARCELABLE_VERSION), apiName);
+ }
+
+ @SmallTest
+ public void testSdkApiLevelSkippedIfGreaterThanAllowed() {
+ int i = 0;
+ if (Build.LINEAGE_VERSION.SDK_INT > Concierge.PARCELABLE_VERSION + 1) {
+ i++;
+ }
+ assertEquals(0, i);
+ }
+
+ @SmallTest
+ public void testSdkLevelRetrieveNameImpossible() {
+ String name = Build.getNameForSDKInt(Integer.MAX_VALUE);
+ assertNotNull(name);
+ assertEquals(Build.UNKNOWN, name);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java b/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java
new file mode 100644
index 00000000..7acfc640
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/ClassPathException.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.versioning.unit;
+
+/**
+ * Created by Adnan on 9/25/15.
+ */
+public class ClassPathException extends Exception {
+
+ public ClassPathException(String message) {
+ super("should not have " + message + " !");
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java b/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java
new file mode 100644
index 00000000..b5c041ed
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/ClassPathTest.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2015, 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.lineageos.tests.versioning.unit;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import dalvik.system.DexFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+/**
+ * Created by adnan on 9/22/15.
+ */
+public class ClassPathTest extends AndroidTestCase {
+
+ private static final String LINEAGEOS_NAMESPACE = "lineageos";
+ private static final String PATH_TO_SYSTEM_FRAMEWORK = "/system/framework";
+
+ private ArrayList<String> mKnownSdkClasses;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKnownSdkClasses = MagicalDexHelper.getLoadedClasses(mContext, LINEAGEOS_NAMESPACE);
+ }
+
+ @SmallTest
+ public void testClassLoaderGivesSDKClasses() {
+ /**
+ * Verify we can retrieve our sdk classes from this package
+ */
+ assertNotNull(mKnownSdkClasses);
+ assertTrue(mKnownSdkClasses.size() > 0);
+ }
+
+ @LargeTest
+ public void testBootClassPathIsClean() {
+ File path = new File(PATH_TO_SYSTEM_FRAMEWORK);
+ File[] files = path.listFiles();
+ assertNotNull(files);
+
+ /**
+ * Everything in the in the boot class path needs to not
+ * contain the sdk. Verify integrity of runtime below.
+ */
+ final String bootClassPath = System.getenv("BOOTCLASSPATH");
+
+ ArrayList<String> classPathJars = new ArrayList<String>();
+
+ if (bootClassPath != null) {
+ String[] bootClassPathElements = bootClassPath.split(":");
+ for (String element : bootClassPathElements) {
+ classPathJars.add(element);
+ }
+ } else {
+ throw new AssertionError("No BOOTCLASSPATH defined! ");
+ }
+
+ for (String classPathJar : classPathJars) {
+ try {
+ File jar = new File(classPathJar);
+ DexFile dexFile = new DexFile(jar);
+ assertTrue(isJarClean(dexFile));
+ } catch (IOException e) {
+ throw new AssertionError("Unable to find jar! " + classPathJar +
+ "\nException " + e.toString());
+ }
+ }
+ }
+
+ private void processAndCompare(String name) throws ClassPathException {
+ if (mKnownSdkClasses.contains(name)) {
+ throw new ClassPathException(name);
+ }
+ }
+
+ private boolean isJarClean(DexFile dexFile) throws AssertionError {
+ Enumeration<String> enumeration = dexFile.entries();
+
+ while (enumeration.hasMoreElements()) {
+ try {
+ processAndCompare(enumeration.nextElement());
+ } catch (ClassPathException e) {
+ throw new AssertionError("Jar file "
+ + dexFile.getName() + " " + e.getMessage());
+ }
+ }
+ return true;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java b/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java
new file mode 100644
index 00000000..ae414f38
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/MagicalDexHelper.java
@@ -0,0 +1,55 @@
+/**
+ * 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.lineageos.tests.versioning.unit;
+
+import android.content.Context;
+import dalvik.system.DexFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+/**
+ * Created by adnan on 2/3/16.
+ */
+public class MagicalDexHelper {
+
+ public static ArrayList<String> getLoadedClasses(Context context, String targetNameSpace) {
+ ArrayList<String> listOfClasses = new ArrayList<String>();
+ try {
+ DexFile dexFile = new DexFile(new File(context.getPackageCodePath()));
+ Enumeration<String> enumeration = dexFile.entries();
+
+ while (enumeration.hasMoreElements()){
+ String className = enumeration.nextElement();
+ if (className.startsWith(targetNameSpace)) {
+ listOfClasses.add(className);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return listOfClasses;
+ }
+
+ public static Class loadClassForNameSpace(Context context,
+ String classToLoad) throws IOException {
+ DexFile dexFile = new DexFile(new File(context.getPackageCodePath()));
+ return dexFile.loadClass(classToLoad, context.getClassLoader());
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java
new file mode 100644
index 00000000..ce98bf6f
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/apiv2/ApiV2PriorReleaseInterfaces.java
@@ -0,0 +1,131 @@
+/**
+ * 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.lineageos.tests.versioning.unit.apiv2;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by adnan on 2/4/16.
+ */
+public class ApiV2PriorReleaseInterfaces {
+ private static Map<String, Map<String, Integer>> mApiMethodsAndValues =
+ new HashMap<String, Map<String, Integer>>();
+
+ //Profiles Aidl (IProfileManager)
+ static {
+ Map<String, Integer> profilesMap = getInternalInterfaceMap("IProfileManager");
+ // APRICOT + BOYSENBERRY + CANTALOUPE
+ profilesMap.put("setActiveProfile", 1);
+ profilesMap.put("etActiveProfileByName", 2);
+ profilesMap.put("getActiveProfile", 3);
+ profilesMap.put("addProfile", 4);
+ profilesMap.put("removeProfile", 5);
+ profilesMap.put("updateProfile", 6);
+ profilesMap.put("getProfile", 7);
+ profilesMap.put("getProfileByName", 8);
+ profilesMap.put("getProfiles", 9);
+ profilesMap.put("profileExists", 10);
+ profilesMap.put("profileExistsByName", 11);
+ profilesMap.put("notificationGroupExistsByName", 12);
+ profilesMap.put("getNotificationGroups", 13);
+ profilesMap.put("addNotificationGroup", 14);
+ profilesMap.put("removeNotificationGroup", 15);
+ profilesMap.put("updateNotificationGroup", 16);
+ profilesMap.put("getNotificationGroupForPackage", 17);
+ profilesMap.put("getNotificationGroup", 18);
+ profilesMap.put("resetAll", 19);
+ }
+
+ //LineageHardwareManager Aidl (ILineageHardwareService)
+ static {
+ Map<String, Integer> hardwareMap = getInternalInterfaceMap("ILineageHardwareService");
+ // APRICOT + BOYSENBERRY + CANTALOUPE
+ hardwareMap.put("getSupportedFeatures", 1);
+ hardwareMap.put("get", 2);
+ hardwareMap.put("set", 3);
+ hardwareMap.put("getDisplayColorCalibration", 4);
+ hardwareMap.put("setDisplayColorCalibration", 5);
+ hardwareMap.put("getNumGammaControls", 6);
+ hardwareMap.put("getDisplayGammaCalibration", 7);
+ hardwareMap.put("setDisplayGammaCalibration", 8);
+ hardwareMap.put("getVibratorIntensity", 9);
+ hardwareMap.put("setVibratorIntensity", 10);
+ hardwareMap.put("getLtoSource", 11);
+ hardwareMap.put("getLtoDestination", 12);
+ hardwareMap.put("getLtoDownloadInterval", 13);
+ hardwareMap.put("getSerialNumber", 14);
+ hardwareMap.put("requireAdaptiveBacklightForSunlightEnhancement", 15);
+ hardwareMap.put("getDisplayModes", 16);
+ hardwareMap.put("getCurrentDisplayMode", 17);
+ hardwareMap.put("getDefaultDisplayMode", 18);
+ hardwareMap.put("setDisplayMode", 19);
+ hardwareMap.put("writePersistentBytes", 20);
+ hardwareMap.put("readPersistentBytes", 21);
+ hardwareMap.put("getThermalState", 22);
+ hardwareMap.put("registerThermalListener", 23);
+ hardwareMap.put("unRegisterThermalListener", 24);
+ }
+
+ //LineageStatusBarManager Aidl (ILineageStatusBarManager)
+ static {
+ Map<String, Integer> statusBarMap = getInternalInterfaceMap("ILineageStatusBarManager");
+ // APRICOT + BOYSENBERRY + CANTALOUPE
+ statusBarMap.put("createCustomTileWithTag", 1);
+ statusBarMap.put("removeCustomTileWithTag", 2);
+ statusBarMap.put("registerListener", 3);
+ statusBarMap.put("unregisterListener", 4);
+ statusBarMap.put("removeCustomTileFromListener", 5);
+ }
+
+ //AppSuggestManager Aidl (IAppSuggestManager)
+ static {
+ Map<String, Integer> suggestMap = getInternalInterfaceMap("IAppSuggestManager");
+ // APRICOT + BOYSENBERRY + CANTALOUPE
+ suggestMap.put("handles", 1);
+ suggestMap.put("getSuggestions", 2);
+ }
+
+ //LineageTelephonyManager Aidl (ILineageTelephonyManager)
+ static {
+ Map<String, Integer> telephonyMap = getInternalInterfaceMap("ILineageTelephonyManager");
+ // APRICOT + BOYSENBERRY + CANTALOUPE
+ telephonyMap.put("getSubInformation", 1);
+ telephonyMap.put("isSubActive", 2);
+ telephonyMap.put("isDataConnectionSelectedOnSub", 3);
+ telephonyMap.put("isDataConnectionEnabled", 4);
+ telephonyMap.put("setSubState", 5);
+ telephonyMap.put("setDataConnectionSelectedOnSub", 6);
+ telephonyMap.put("setDataConnectionState", 7);
+ telephonyMap.put("setDefaultPhoneSub", 8);
+ telephonyMap.put("setDefaultSmsSub", 9);
+ }
+
+ protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) {
+ Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface);
+ if (internalMap == null) {
+ internalMap = new HashMap<String, Integer>();
+ mApiMethodsAndValues.put(targetInterface, internalMap);
+ return internalMap;
+ }
+ return internalMap;
+ }
+
+ public static Map<String, Map<String, Integer>> getInterfaces() {
+ return mApiMethodsAndValues;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java
new file mode 100644
index 00000000..3e29d58b
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/apiv4/ApiV4PriorReleaseInterfaces.java
@@ -0,0 +1,107 @@
+/**
+ * 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.lineageos.tests.versioning.unit.apiv4;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ApiV4PriorReleaseInterfaces {
+ private static Map<String, Map<String, Integer>> mApiMethodsAndValues =
+ new HashMap<String, Map<String, Integer>>();
+
+ //Profiles Aidl (IProfileManager)
+ static {
+ Map<String, Integer> profilesMap = getInternalInterfaceMap("IProfileManager");
+ // APRICOT + BOYSENBERRY + CANTALOUPE to 19
+ // DRAGONFRUIT BEGIN
+ profilesMap.put("isEnabled", 20);
+ }
+
+ //LineageHardwareManager Aidl (ILineageHardwareService)
+ static {
+ Map<String, Integer> hardwareMap = getInternalInterfaceMap("ILineageHardwareService");
+ // APRICOT + BOYSENBERRY + CANTALOUPE to 24
+ // DRAGONFRUIT BEGIN
+ hardwareMap.put("isSunlightEnhancementSelfManaged", 25);
+ hardwareMap.put("getUniqueDeviceId", 26);
+ }
+
+ //LineageStatusBarManager Aidl (ILineageStatusBarManager)
+ static {
+ // APRICOT + BOYSENBERRY + CANTALOUPE to 5
+ // DRAGONFRUIT BEGIN
+ }
+
+ //AppSuggestManager Aidl (IAppSuggestManager)
+ static {
+ // APRICOT + BOYSENBERRY + CANTALOUPE to 2
+ // DRAGONFRUIT BEGIN
+ }
+
+ //LineageTelephonyManager Aidl (ILineageTelephonyManager)
+ static {
+ // APRICOT + BOYSENBERRY + CANTALOUPE to 9
+ // DRAGONFRUIT BEGIN
+ }
+
+ //PerformanceManager Aidl (IPerformanceManager)
+ static {
+ Map<String, Integer> perfMap = getInternalInterfaceMap("IPerformanceManager");
+ // DRAGONFRUIT BEGIN
+ perfMap.put("cpuBoost", 1);
+ perfMap.put("setPowerProfile", 2);
+ perfMap.put("getPowerProfile", 3);
+ perfMap.put("getNumberOfProfiles", 4);
+ perfMap.put("getProfileHasAppProfiles", 5);
+ }
+
+ //ExternalViewProviderFactory Aidl (IExternalViewProviderFactory)
+ static {
+ Map<String, Integer> extProviderMap =
+ getInternalInterfaceMap("IExternalViewProviderFactory");
+ // DRAGONFRUIT BEGIN
+ extProviderMap.put("createExternalView", 1);
+ }
+
+ //ExternalViewProvider Aidl (IExternalViewProvider)
+ static {
+ Map<String, Integer> extViewProviderMap =
+ getInternalInterfaceMap("IExternalViewProvider");
+ // DRAGONFRUIT BEGIN
+ extViewProviderMap.put("onAttach", 1);
+ extViewProviderMap.put("onStart", 2);
+ extViewProviderMap.put("onResume", 3);
+ extViewProviderMap.put("onPause", 4);
+ extViewProviderMap.put("onStop", 5);
+ extViewProviderMap.put("onDetach", 6);
+ extViewProviderMap.put("alterWindow", 7);
+ }
+
+ protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) {
+ Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface);
+ if (internalMap == null) {
+ internalMap = new HashMap<String, Integer>();
+ mApiMethodsAndValues.put(targetInterface, internalMap);
+ return internalMap;
+ }
+ return internalMap;
+ }
+
+ public static Map<String, Map<String, Integer>> getInterfaces() {
+ return mApiMethodsAndValues;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java b/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java
new file mode 100644
index 00000000..898dbfad
--- /dev/null
+++ b/tests/src/org/lineageos/tests/versioning/unit/apiv5/ApiV5PriorReleaseInterfaces.java
@@ -0,0 +1,113 @@
+/**
+ * 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.lineageos.tests.versioning.unit.apiv5;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ApiV5PriorReleaseInterfaces {
+ private static Map<String, Map<String, Integer>> mApiMethodsAndValues =
+ new HashMap<String, Map<String, Integer>>();
+
+ //ExternalViewProviderFactory Aidl (IExternalViewProviderFactory)
+ static {
+ Map<String, Integer> extProviderMap =
+ getInternalInterfaceMap("IExternalViewProviderFactory");
+ // DRAGONFRUIT TO 1
+ // ELDERBERRY BEGIN
+ }
+
+ //ExternalViewProvider Aidl (IExternalViewProvider)
+ static {
+ Map<String, Integer> extViewProviderMap =
+ getInternalInterfaceMap("IExternalViewProvider");
+ // DRAGONFRUIT TO 7
+ // ELDERBERRY BEGIN
+ }
+
+ //LineageAudioManager Aidl (ILineageAudioService)
+ static {
+ Map<String, Integer> lineageAudioService =
+ getInternalInterfaceMap("ILineageAudioService");
+ //ELDERBERRY BEGIN
+ lineageAudioService.put("listAudioSessions", 1);
+ }
+
+ //LineageWeatherManager Aidl (ILineageWeatherManager)
+ static {
+ Map<String, Integer> ilineageWeatherManager =
+ getInternalInterfaceMap("ILineageWeatherManager");
+ //ELDERBERRY BEGIN
+ ilineageWeatherManager.put("updateWeather", 1);
+ ilineageWeatherManager.put("lookupCity ", 2);
+ ilineageWeatherManager.put("registerWeatherServiceProviderChangeListener", 3);
+ ilineageWeatherManager.put("unregisterWeatherServiceProviderChangeListener", 4);
+ ilineageWeatherManager.put("getActiveWeatherServiceProviderLabel", 5);
+ ilineageWeatherManager.put("cancelRequest", 6);
+ }
+
+ //RequestInfoListener Aidl (IRequestInfoListener)
+ static {
+ Map<String, Integer> requestInfoListener =
+ getInternalInterfaceMap("IRequestInfoListener");
+ //ELDERBERRY BEGIN
+ requestInfoListener.put("onWeatherRequestCompleted", 1);
+ requestInfoListener.put("onLookupCityRequestCompleted ", 2);
+ }
+
+ //WeatherServiceProviderChangeListener Aidl (IWeatherServiceProviderChangeListener)
+ static {
+ Map<String, Integer> weatherServiceProviderChangeListener =
+ getInternalInterfaceMap("IWeatherServiceProviderChangeListener");
+ //ELDERBERRY BEGIN
+ weatherServiceProviderChangeListener.put("onWeatherServiceProviderChanged", 1);
+ }
+
+ //WeatherProviderService Aidl (IWeatherProviderService)
+ static {
+ Map<String, Integer> weatherProviderService =
+ getInternalInterfaceMap("IWeatherProviderService");
+ //ELDERBERRY BEGIN
+ weatherProviderService.put("processWeatherUpdateRequest", 1);
+ weatherProviderService.put("processCityNameLookupRequest ", 2);
+ weatherProviderService.put("setServiceClient", 3);
+ weatherProviderService.put("cancelOngoingRequests", 4);
+ weatherProviderService.put("cancelRequest", 5);
+ }
+
+ //WeatherProviderServiceClient Aidl (IWeatherProviderServiceClient)
+ static {
+ Map<String, Integer> weatherProviderServiceClient =
+ getInternalInterfaceMap("IWeatherProviderServiceClient");
+ //ELDERBERRY BEGIN
+ weatherProviderServiceClient.put("setServiceRequestState", 1);
+ }
+
+ protected static Map<String, Integer> getInternalInterfaceMap(String targetInterface) {
+ Map<String, Integer> internalMap = mApiMethodsAndValues.get(targetInterface);
+ if (internalMap == null) {
+ internalMap = new HashMap<String, Integer>();
+ mApiMethodsAndValues.put(targetInterface, internalMap);
+ return internalMap;
+ }
+ return internalMap;
+ }
+
+ public static Map<String, Map<String, Integer>> getInterfaces() {
+ return mApiMethodsAndValues;
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java
new file mode 100644
index 00000000..70a8c7ea
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/DayForecastBuilderTest.java
@@ -0,0 +1,108 @@
+/**
+ * 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.lineageos.tests.weather.unit;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.providers.WeatherContract;
+import lineageos.weather.WeatherInfo.DayForecast;
+
+public class DayForecastBuilderTest extends AndroidTestCase {
+
+ private static final int mConditionCode = WeatherContract.WeatherColumns.WeatherCode.HURRICANE;
+ private static final double mLow = 35;
+ private static final double mHigh = 58;
+
+ @SmallTest
+ public void testUnravelFromParcel() {
+ DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh).setLow(mLow)
+ .build();
+
+ Parcel parcel = Parcel.obtain();
+ forecast.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ DayForecast forecastFromParcel = DayForecast.CREATOR.createFromParcel(parcel);
+
+ assertEquals(forecast, forecastFromParcel);
+ assertEquals(forecast.getConditionCode(), forecastFromParcel.getConditionCode());
+ assertEquals(forecast.getHigh(), forecastFromParcel.getHigh());
+ assertEquals(forecast.getLow(), forecastFromParcel.getLow());
+ }
+
+ @SmallTest
+ public void testUnravelFromParcelWithDefaultValues() {
+ //Condition code is required
+ DayForecast forecast = new DayForecast.Builder(mConditionCode).build();
+
+ Parcel parcel = Parcel.obtain();
+ forecast.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ DayForecast forecastFromParcel = DayForecast.CREATOR.createFromParcel(parcel);
+
+ assertEquals(forecast, forecastFromParcel);
+ assertEquals(forecast.getConditionCode(), forecastFromParcel.getConditionCode());
+ assertEquals(forecast.getHigh(), forecastFromParcel.getHigh());
+ assertEquals(forecast.getLow(), forecastFromParcel.getLow());
+ }
+
+ @SmallTest
+ public void testDayForecastBuilder() {
+ DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh).setLow(mLow)
+ .build();
+
+ assertEquals(forecast.getConditionCode(), mConditionCode);
+ assertEquals(forecast.getHigh(), mHigh);
+ assertEquals(forecast.getLow(), mLow);
+ }
+
+ @SmallTest
+ public void testInvalidWeatherConditionCode() {
+ try {
+ DayForecast forecast = new DayForecast.Builder(Integer.MIN_VALUE).build();
+ throw new AssertionError("DayForecast object was built with invalid condition code!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidHighTemperature() {
+ try {
+ DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(Double.NaN)
+ .setLow(mLow).build();
+ throw new AssertionError("DayForecast object was built with invalid high temperature!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidLowTemperature() {
+ try {
+ DayForecast forecast = new DayForecast.Builder(mConditionCode).setHigh(mHigh)
+ .setLow(Double.NaN).build();
+ throw new AssertionError("DayForecast object was built with invalid low temperature!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java b/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java
new file mode 100644
index 00000000..f6b23484
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/LineageWeatherManagerTest.java
@@ -0,0 +1,242 @@
+/**
+ * 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.lineageos.tests.weather.unit;
+
+import android.location.Location;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.weather.LineageWeatherManager;
+import lineageos.weather.LineageWeatherManager.LookupCityRequestListener;
+import lineageos.weather.LineageWeatherManager.WeatherServiceProviderChangeListener;
+import lineageos.weather.LineageWeatherManager.WeatherUpdateRequestListener;
+import lineageos.weather.ILineageWeatherManager;
+import lineageos.weather.RequestInfo;
+import lineageos.weather.WeatherInfo;
+import lineageos.weather.WeatherLocation;
+import org.lineageos.tests.common.MockIBinderStubForInterface;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+public class LineageWeatherManagerTest extends AndroidTestCase {
+
+ private LineageWeatherManager mWeatherManager;
+ private static final String CITY_NAME = "Seattle, WA";
+ private static final int COUNTDOWN = 1;
+ private static final int REQUEST_ID = 42;
+ private static final String MOCKED_WEATHER_PROVIDER_LABEL = "Mock'd Weather Service";
+ private ILineageWeatherManager.Stub mILineageWeatherManagerSpy;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setUpMockILineageWeatherManager();
+ }
+
+ private void setUpMockILineageWeatherManager() {
+ mWeatherManager = LineageWeatherManager.getInstance(getContext());
+ Field f;
+ try {
+ f = mWeatherManager.getClass().getDeclaredField("sWeatherManagerService");
+ f.setAccessible(true);
+
+ mILineageWeatherManagerSpy
+ = MockIBinderStubForInterface.getMockInterface(ILineageWeatherManager.Stub.class);
+ f.set(mWeatherManager, mILineageWeatherManagerSpy);
+
+ Mockito.doAnswer(new WeatherUpdateRequestAnswer())
+ .when(mILineageWeatherManagerSpy).updateWeather(Mockito.any(RequestInfo.class));
+
+ Mockito.doAnswer(new LookUpCityAnswer())
+ .when(mILineageWeatherManagerSpy).lookupCity(Mockito.any(RequestInfo.class));
+
+ Mockito.doAnswer(new GetActiveWeatherServiceProviderLabelAnser())
+ .when(mILineageWeatherManagerSpy).getActiveWeatherServiceProviderLabel();
+
+ Mockito.doAnswer(new CancelRequestAnswer())
+ .when(mILineageWeatherManagerSpy).cancelRequest(Mockito.eq(REQUEST_ID));
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static class WeatherUpdateRequestAnswer implements Answer<Integer> {
+
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ final RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0];
+ if (requestInfo.getRequestType() == RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ) {
+ assertNotNull(requestInfo.getLocation());
+ } else {
+ assertNotNull(requestInfo.getWeatherLocation());
+ }
+ final WeatherInfo weatherInfo = new WeatherInfo.Builder(CITY_NAME,
+ 30d, requestInfo.getTemperatureUnit()).build();
+ requestInfo.getRequestListener().onWeatherRequestCompleted(requestInfo,
+ LineageWeatherManager.RequestStatus.COMPLETED, weatherInfo);
+ return REQUEST_ID;
+ }
+ }
+
+ private static class LookUpCityAnswer implements Answer<Integer> {
+
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ final RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0];
+ final List<WeatherLocation> locations = new ArrayList<>();
+ final String cityName = requestInfo.getCityName();
+ assertNotNull(cityName);
+ locations.add(new WeatherLocation.Builder(cityName).build());
+ requestInfo.getRequestListener().onLookupCityRequestCompleted(requestInfo,
+ LineageWeatherManager.RequestStatus.COMPLETED, locations);
+ return REQUEST_ID;
+ }
+ }
+
+ private static class GetActiveWeatherServiceProviderLabelAnser implements Answer<String> {
+
+ @Override
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ return MOCKED_WEATHER_PROVIDER_LABEL;
+ }
+ }
+
+ private static class CancelRequestAnswer implements Answer<Void> {
+
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ final int requestId = (Integer) invocation.getArguments()[0];
+ assertEquals(requestId, REQUEST_ID);
+ return null;
+ }
+ }
+
+ @SmallTest
+ public void testGetActiveWeatherServiceProviderLabel() {
+ String providerLabel = mWeatherManager.getActiveWeatherServiceProviderLabel();
+ assertEquals(MOCKED_WEATHER_PROVIDER_LABEL, providerLabel);
+ }
+
+ @MediumTest
+ public void testLookupCity() {
+ final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
+ final boolean[] error = {false};
+ mWeatherManager.lookupCity(CITY_NAME,
+ new LookupCityRequestListener() {
+ @Override
+ public void onLookupCityRequestCompleted(int status,
+ List<WeatherLocation> locations) {
+ final int totalLocations = locations != null ? locations.size() : 0;
+ if (status != LineageWeatherManager.RequestStatus.COMPLETED
+ || totalLocations < 1) {
+ error[0] = true;
+ }
+ signal.countDown();
+ }
+ });
+ try {
+ signal.await();
+ assertFalse(error[0]);
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @SmallTest
+ public void testRegisterListener() {
+ mWeatherManager.registerWeatherServiceProviderChangeListener(mListener);
+
+ try {
+ mWeatherManager.registerWeatherServiceProviderChangeListener(mListener);
+ throw new AssertionError("Listener was registered twice!");
+ } catch (IllegalArgumentException e) {
+ //EXPECTED
+ }
+
+ mWeatherManager.unregisterWeatherServiceProviderChangeListener(mListener);
+
+ try {
+ mWeatherManager.unregisterWeatherServiceProviderChangeListener(mListener);
+ throw new AssertionError("Listener was de-registered twice!");
+ } catch (IllegalArgumentException e) {
+ //EXPECTED
+ }
+ }
+
+ private WeatherServiceProviderChangeListener mListener
+ = new WeatherServiceProviderChangeListener() {
+ @Override
+ public void onWeatherServiceProviderChanged(String providerLabel) {}
+ };
+
+ @MediumTest
+ public void testRequestWeatherUpdateByWeatherLocation() {
+ final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
+ final WeatherLocation weatherLocation = new WeatherLocation.Builder(CITY_NAME).build();
+ final boolean[] error = {false};
+ mWeatherManager.requestWeatherUpdate(weatherLocation, new WeatherUpdateRequestListener() {
+ @Override
+ public void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo) {
+ if (status != LineageWeatherManager.RequestStatus.COMPLETED
+ || !weatherInfo.getCity().equals(CITY_NAME)) {
+ error[0] = true;
+ }
+ signal.countDown();
+ }
+ });
+ try {
+ signal.await();
+ assertFalse(error[0]);
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @MediumTest
+ public void testRequestWeatherUpdateByLocation() {
+ final CountDownLatch signal = new CountDownLatch(COUNTDOWN);
+ final Location location = new Location("test_location_provider");
+ final boolean[] error = {false};
+ mWeatherManager.requestWeatherUpdate(location, new WeatherUpdateRequestListener() {
+ @Override
+ public void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo) {
+ if (status != LineageWeatherManager.RequestStatus.COMPLETED
+ || !weatherInfo.getCity().equals(CITY_NAME)) {
+ error[0] = true;
+ }
+ signal.countDown();
+ }
+ });
+ try {
+ signal.await();
+ assertFalse(error[0]);
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @SmallTest
+ public void testCancelRequest() {
+ mWeatherManager.cancelRequest(REQUEST_ID);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java b/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java
new file mode 100644
index 00000000..83f6d6ea
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/MockWeatherProviderService.java
@@ -0,0 +1,54 @@
+/*
+ * 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.lineageos.tests.weather.unit;
+
+import lineageos.weatherservice.ServiceRequest;
+import lineageos.weatherservice.WeatherProviderService;
+import org.mockito.Mockito;
+
+public class MockWeatherProviderService extends WeatherProviderService {
+
+ private MockWeatherProviderService mCallTracker;
+
+ public MockWeatherProviderService() {
+ mCallTracker = Mockito.mock(MockWeatherProviderService.class);
+ }
+
+ public MockWeatherProviderService getCallTracker() {
+ return mCallTracker;
+ }
+
+ @Override
+ protected void onConnected() {
+ mCallTracker.onConnected();
+ }
+
+ @Override
+ protected void onDisconnected() {
+ mCallTracker.onDisconnected();
+ }
+
+ @Override
+ protected void onRequestSubmitted(ServiceRequest request) {
+ mCallTracker.onRequestSubmitted(request);
+ }
+
+ @Override
+ protected void onRequestCancelled(ServiceRequest request) {
+ mCallTracker.onRequestCancelled(request);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java
new file mode 100644
index 00000000..1befff61
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/ServiceRequestResultBuilderTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.lineageos.tests.weather.unit;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.providers.WeatherContract;
+import lineageos.weather.WeatherInfo;
+import lineageos.weather.WeatherLocation;
+import lineageos.weatherservice.ServiceRequestResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ServiceRequestResultBuilderTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testUnravelFromParcelWithWeatherInfo() {
+ final String cityName = "Cancun";
+ final double temperature = 70;
+ final int temperatureUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS;
+
+ WeatherInfo info = new WeatherInfo.Builder(cityName, temperature, temperatureUnit)
+ .build();
+
+ ServiceRequestResult result = new ServiceRequestResult.Builder(info).build();
+
+ Parcel parcel = Parcel.obtain();
+ result.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ ServiceRequestResult resultFromParcel
+ = ServiceRequestResult.CREATOR.createFromParcel(parcel);
+
+ assertEquals(result, resultFromParcel);
+ assertEquals(result.getWeatherInfo(), resultFromParcel.getWeatherInfo());
+ }
+
+ @SmallTest
+ public void testsUnravelFromParcelWithWeatherLocationList() {
+
+ List<WeatherLocation> weatherLocationList = new ArrayList<>();
+ weatherLocationList.add(new WeatherLocation.Builder("Cancun").build());
+ ServiceRequestResult result = new ServiceRequestResult.Builder(weatherLocationList).build();
+
+ Parcel parcel = Parcel.obtain();
+ result.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ ServiceRequestResult resultFromParcel
+ = ServiceRequestResult.CREATOR.createFromParcel(parcel);
+
+ assertEquals(result, resultFromParcel);
+ assertEquals(result.getLocationLookupList(), resultFromParcel.getLocationLookupList());
+ }
+
+ @SmallTest
+ public void testNullWeatherInfo() {
+ try {
+ WeatherInfo info = null;
+ ServiceRequestResult result = new ServiceRequestResult.Builder(info).build();
+ throw new AssertionError("ServiceRequestResult object was built with null WeatherInfo");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testNullWeatherLocationList() {
+ try {
+ List<WeatherLocation> list = null;
+ ServiceRequestResult result = new ServiceRequestResult.Builder(list).build();
+ throw new AssertionError("ServiceRequestResult object was built with null "
+ + "WeatherLocation list");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java
new file mode 100644
index 00000000..bc1dd100
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/WeatherInfoBuilderTest.java
@@ -0,0 +1,252 @@
+/**
+ * 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.lineageos.tests.weather.unit;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.providers.WeatherContract;
+import lineageos.weather.WeatherInfo;
+
+public class WeatherInfoBuilderTest extends AndroidTestCase {
+
+ private static final String mCityName = "Cancun";
+ private static final double mTemperature = 70;
+ private static final int mTemperatureUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS;
+ private static final double mHumidity = 45;
+ private static final double mWindSpeed = 15;
+ private static final double mWindDirection = 150;
+ private static final int mWindSpeedUnit = WeatherContract.WeatherColumns.WindSpeedUnit.KPH;
+ private static final long mTimestamp = System.currentTimeMillis();
+ private static final double mTodaysHigh = 80;
+ private static final double mTodaysLow = 65;
+ private static final int mWeatherConditionCode
+ = WeatherContract.WeatherColumns.WeatherCode.SUNNY;
+
+ @SmallTest
+ public void testUnravelFromParcelWithDefaultValues() {
+ //City name, temp and unit are required
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit)
+ .build();
+ Parcel parcel = Parcel.obtain();
+ info.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherInfo weatherInfoFromParcel = WeatherInfo.CREATOR.createFromParcel(parcel);
+ assertNotNull(weatherInfoFromParcel);
+
+ assertEquals(info, weatherInfoFromParcel);
+ //City name
+ assertEquals(info.getCity(), weatherInfoFromParcel.getCity());
+ //Forecast list
+ assertEquals(info.getForecasts(), weatherInfoFromParcel.getForecasts());
+ //Humidity
+ assertEquals(info.getHumidity(), weatherInfoFromParcel.getHumidity());
+ //Temp
+ assertEquals(info.getConditionCode(), weatherInfoFromParcel.getConditionCode());
+ assertEquals(info.getTemperature(), weatherInfoFromParcel.getTemperature());
+ assertEquals(info.getTemperatureUnit(), weatherInfoFromParcel.getTemperatureUnit());
+ //Timestamp
+ assertEquals(info.getTimestamp(), weatherInfoFromParcel.getTimestamp());
+ //Today's low/high
+ assertEquals(info.getTodaysHigh(), weatherInfoFromParcel.getTodaysHigh());
+ assertEquals(info.getTodaysLow(), weatherInfoFromParcel.getTodaysLow());
+ //Wind
+ assertEquals(info.getWindDirection(), weatherInfoFromParcel.getWindDirection());
+ assertEquals(info.getWindSpeed(), weatherInfoFromParcel.getWindDirection());
+ assertEquals(info.getWindSpeedUnit(), weatherInfoFromParcel.getWindSpeedUnit());
+ //Verify default values
+ assertEquals(info.getTodaysHigh(), Double.NaN);
+ }
+
+ @SmallTest
+ public void testWeatherInfoBuilder() {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit)
+ .setHumidity(mHumidity)
+ .setWind(mWindSpeed, mWindDirection, mWindSpeedUnit)
+ .setTimestamp(mTimestamp)
+ .setTodaysHigh(mTodaysHigh)
+ .setTodaysLow(mTodaysLow)
+ .setWeatherCondition(mWeatherConditionCode).build();
+
+ assertEquals(info.getCity(), mCityName);
+ assertEquals(info.getTemperature(), mTemperature);
+ assertEquals(info.getTemperatureUnit(), mTemperatureUnit);
+ assertEquals(info.getHumidity(), mHumidity);
+ assertEquals(info.getWindSpeed(), mWindSpeed);
+ assertEquals(info.getWindDirection(), mWindDirection);
+ assertEquals(info.getWindSpeedUnit(), mWindSpeedUnit);
+ assertEquals(info.getTimestamp(), mTimestamp);
+ assertEquals(info.getTodaysHigh(), mTodaysHigh);
+ assertEquals(info.getTodaysLow(), mTodaysLow);
+ assertEquals(info.getConditionCode(), mWeatherConditionCode);
+ }
+
+ @SmallTest
+ public void testUnravelFromParcel() {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature, mTemperatureUnit)
+ .setHumidity(mHumidity)
+ .setWind(mWindSpeed, mWindDirection, mWindSpeedUnit)
+ .setTimestamp(mTimestamp)
+ .setTodaysHigh(mTodaysHigh)
+ .setTodaysLow(mTodaysLow)
+ .setWeatherCondition(mWeatherConditionCode).build();
+
+ Parcel parcel = Parcel.obtain();
+ info.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherInfo infoFromParcel = WeatherInfo.CREATOR.createFromParcel(parcel);
+ assertEquals(info.getCity(), infoFromParcel.getCity());
+ assertEquals(info.getTemperature(), infoFromParcel.getTemperature());
+ assertEquals(info.getTemperatureUnit(), infoFromParcel.getTemperatureUnit());
+ assertEquals(info.getHumidity(), infoFromParcel.getHumidity());
+ assertEquals(info.getWindSpeed(), infoFromParcel.getWindSpeed());
+ assertEquals(info.getWindDirection(), infoFromParcel.getWindDirection());
+ assertEquals(info.getWindSpeedUnit(), infoFromParcel.getWindSpeedUnit());
+ assertEquals(info.getTimestamp(), infoFromParcel.getTimestamp());
+ assertEquals(info.getTodaysHigh(), infoFromParcel.getTodaysHigh());
+ assertEquals(info.getTodaysLow(), infoFromParcel.getTodaysLow());
+ assertEquals(info.getConditionCode(), infoFromParcel.getConditionCode());
+ }
+
+ @SmallTest
+ public void testNullCityName() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(null, mTemperature, mTemperatureUnit)
+ .build();
+ throw new AssertionError("WeatherInfo object built with null city name!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidTemperature() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, Double.NaN, mTemperatureUnit)
+ .build();
+ throw new AssertionError("WeatherInfo object built with invalid temperature value!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidTemperatureUnit() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,Integer.MIN_VALUE)
+ .build();
+ throw new AssertionError("WeatherInfo object built with invalid temperature unit!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testNullForecastList() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setForecast(null).build();
+ throw new AssertionError("WeatherInfo object built with null forecast list!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidWeatherConditionCode() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setWeatherCondition(Integer.MIN_VALUE).build();
+ throw new AssertionError("WeatherInfo object built with invalid weather "
+ + "condition code!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidHumidity() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setHumidity(Double.NaN).build();
+ throw new AssertionError("WeatherInfo object built with invalid humidity value!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidWindSpeed() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setWind(Double.NaN, mWindDirection, mWindSpeedUnit)
+ .build();
+ throw new AssertionError("WeatherInfo object built with invalid wind speed!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidWindDirection() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setWind(mWindSpeed, Double.NaN, mWindSpeedUnit)
+ .build();
+ throw new AssertionError("WeatherInfo object built with invalid wind direction!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidWindSpeedUnit(){
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setWind(mWindSpeed, mWindDirection, Integer.MIN_VALUE).build();
+ throw new AssertionError("WeatherInfo object built with invalid wind speed unit!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidTodaysLow() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setTodaysLow(Double.NaN).build();
+ throw new AssertionError("WeatherInfo object built with invalid low temp!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+
+ @SmallTest
+ public void testInvalidTodaysHigh() {
+ try {
+ WeatherInfo info = new WeatherInfo.Builder(mCityName, mTemperature,mTemperatureUnit)
+ .setTodaysHigh(Double.NaN).build();
+ throw new AssertionError("WeatherInfo object built with invalid high temp!");
+ } catch (IllegalArgumentException e) {
+ /* EXPECTED */
+ }
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java
new file mode 100644
index 00000000..b6d9c207
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/WeatherLocationBuilderTest.java
@@ -0,0 +1,129 @@
+/**
+ * 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.lineageos.tests.weather.unit;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import lineageos.weather.WeatherLocation;
+
+public class WeatherLocationBuilderTest extends AndroidTestCase {
+
+ private static final String mCityId = "can1";
+ private static final String mCityName = "Cancun";
+ private static final String mState = "Quintana Roo";
+ private static final String mCountryId = "MX";
+ private static final String mCountry = "Mexico";
+ private static final String mZipCode = "77510";
+
+ @SmallTest
+ public void testUnravelFromParcelTwoArgsConstructor() {
+ WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName)
+ .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId)
+ .setCountry(mCountry).build();
+
+ Parcel parcel = Parcel.obtain();
+ location.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(location, locationFromParcel);
+ assertEquals(location.getCityId(), locationFromParcel.getCityId());
+ assertEquals(location.getCity(), locationFromParcel.getCity());
+ assertEquals(location.getState(), locationFromParcel.getState());
+ assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode());
+ assertEquals(location.getCountry(), locationFromParcel.getCountry());
+ assertEquals(location.getCountryId(), locationFromParcel.getCountryId());
+ }
+
+ @SmallTest
+ public void testUnravelFromParcelOneArgConstructor() {
+ WeatherLocation location = new WeatherLocation.Builder(mCityName)
+ .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId)
+ .setCountry(mCountry).build();
+
+ Parcel parcel = Parcel.obtain();
+ location.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(location, locationFromParcel);
+ assertEquals(location.getCityId(), locationFromParcel.getCityId());
+ assertEquals(location.getCity(), locationFromParcel.getCity());
+ assertEquals(location.getState(), locationFromParcel.getState());
+ assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode());
+ assertEquals(location.getCountry(), locationFromParcel.getCountry());
+ assertEquals(location.getCountryId(), locationFromParcel.getCountryId());
+ }
+
+ @SmallTest
+ public void testUnravelFromParcelWithDefaultsOneArgConstructor() {
+ WeatherLocation location = new WeatherLocation.Builder(mCityName).build();
+ Parcel parcel = Parcel.obtain();
+ location.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(location, locationFromParcel);
+ assertEquals(location.getCityId(), locationFromParcel.getCityId());
+ assertEquals(location.getCity(), locationFromParcel.getCity());
+ assertEquals(location.getState(), locationFromParcel.getState());
+ assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode());
+ assertEquals(location.getCountry(), locationFromParcel.getCountry());
+ assertEquals(location.getCountryId(), locationFromParcel.getCountryId());
+ }
+
+ @SmallTest
+ public void testUnravelFromParcelWithDefaultsTwoArgsConstructor() {
+ WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName).build();
+ Parcel parcel = Parcel.obtain();
+ location.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0);
+
+ WeatherLocation locationFromParcel = WeatherLocation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(location, locationFromParcel);
+ assertEquals(location.getCityId(), locationFromParcel.getCityId());
+ assertEquals(location.getCity(), locationFromParcel.getCity());
+ assertEquals(location.getState(), locationFromParcel.getState());
+ assertEquals(location.getPostalCode(), locationFromParcel.getPostalCode());
+ assertEquals(location.getCountry(), locationFromParcel.getCountry());
+ assertEquals(location.getCountryId(), locationFromParcel.getCountryId());
+ }
+
+
+ @SmallTest
+ public void testWeatherLocationBuilder() {
+ WeatherLocation location = new WeatherLocation.Builder(mCityId, mCityName)
+ .setState(mState).setPostalCode(mZipCode).setCountryId(mCountryId)
+ .setCountry(mCountry).build();
+
+ assertEquals(location.getCityId(), mCityId);
+ assertEquals(location.getCity(), mCityName);
+ assertEquals(location.getState(), mState);
+ assertEquals(location.getPostalCode(), mZipCode);
+ assertEquals(location.getCountryId(), mCountryId);
+ assertEquals(location.getCountry(), mCountry);
+ }
+}
diff --git a/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java b/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java
new file mode 100644
index 00000000..bce369d4
--- /dev/null
+++ b/tests/src/org/lineageos/tests/weather/unit/WeatherProviderServiceTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.lineageos.tests.weather.unit;
+
+import android.location.Location;
+import android.os.IBinder;
+import lineageos.weather.LineageWeatherManager;
+import lineageos.weather.RequestInfo;
+import lineageos.weather.WeatherLocation;
+import lineageos.weatherservice.IWeatherProviderService;
+import lineageos.weatherservice.IWeatherProviderServiceClient;
+import lineageos.weatherservice.ServiceRequest;
+import lineageos.weatherservice.ServiceRequestResult;
+import org.lineageos.tests.common.MockIBinderStubForInterface;
+import org.lineageos.tests.common.ThreadServiceTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+public class WeatherProviderServiceTest extends ThreadServiceTestCase<MockWeatherProviderService> {
+
+ public WeatherProviderServiceTest() {
+ super(MockWeatherProviderService.class);
+ }
+
+ private static final String CITY_NAME = "Seattle";
+ private static final int TIMEOUT = 5000;
+
+ public void testCityNameLookupRequest() throws Exception {
+ IBinder binder = bindService((ServiceRunnable) null);
+ assertNotNull(binder);
+
+ final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder);
+ assertNotNull(provider);
+
+ provider.processCityNameLookupRequest(
+ buildMockdRequestInfo(RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ));
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+ assertEquals(request.getRequestInfo().getRequestType(),
+ RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ);
+
+ assertEquals(request.getRequestInfo().getCityName(), CITY_NAME);
+ }
+ });
+ }
+
+ public void testWeatherUpdateRequestByWeatherLocation() throws Exception {
+ IBinder binder = bindService((ServiceRunnable) null);
+ assertNotNull(binder);
+
+ final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder);
+ assertNotNull(provider);
+
+ provider.processWeatherUpdateRequest(
+ buildMockdRequestInfo(RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ));
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+ assertEquals(request.getRequestInfo().getRequestType(),
+ RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ);
+
+ WeatherLocation weatherLocation = request.getRequestInfo().getWeatherLocation();
+ assertNotNull(weatherLocation);
+ assertEquals(weatherLocation.getCity(), CITY_NAME);
+ }
+ });
+ }
+
+ public void testWeatherUpdateRequestByGeoLocation() throws Exception {
+ IBinder binder = bindService((ServiceRunnable) null);
+ assertNotNull(binder);
+
+ final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder);
+ assertNotNull(provider);
+
+ provider.processWeatherUpdateRequest(
+ buildMockdRequestInfo(RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ));
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+ assertEquals(request.getRequestInfo().getRequestType(),
+ RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ);
+
+ Location location = request.getRequestInfo().getLocation();
+ assertNotNull(location);
+ }
+ });
+ }
+
+ public void testServiceRequestResult() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(3);
+ IBinder binder = bindService((ServiceRunnable) null);
+ assertNotNull(binder);
+
+ final IWeatherProviderService provider = IWeatherProviderService.Stub.asInterface(binder);
+ assertNotNull(provider);
+
+ IWeatherProviderServiceClient client =
+ MockIBinderStubForInterface.getMockInterface(
+ IWeatherProviderServiceClient.Stub.class);
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0];
+ int result = (int) invocation.getArguments()[2];
+
+ assertNotNull(requestInfo);
+ assertEquals(result, LineageWeatherManager.RequestStatus.FAILED);
+
+ latch.countDown();
+ return null;
+ }
+ }).when(client)
+ .setServiceRequestState(Mockito.any(RequestInfo.class),
+ Mockito.any(ServiceRequestResult.class),
+ Mockito.eq(LineageWeatherManager.RequestStatus.FAILED));
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+
+ RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0];
+ int result = (int) invocation.getArguments()[2];
+
+ assertNotNull(requestInfo);
+ assertEquals(result, LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON);
+
+ latch.countDown();
+ return null;
+ }
+ }).when(client)
+ .setServiceRequestState(Mockito.any(RequestInfo.class),
+ Mockito.any(ServiceRequestResult.class),
+ Mockito.eq(LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON));
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ RequestInfo requestInfo = (RequestInfo) invocation.getArguments()[0];
+ ServiceRequestResult requestResult
+ = (ServiceRequestResult) invocation.getArguments()[1];
+ int result = (int) invocation.getArguments()[2];
+
+ assertNotNull(requestInfo);
+ assertNotNull(requestResult);
+ assertNotNull(requestResult.getLocationLookupList());
+ assertEquals(result, LineageWeatherManager.RequestStatus.COMPLETED);
+
+ latch.countDown();
+ return null;
+ }
+ }).when(client)
+ .setServiceRequestState(Mockito.any(RequestInfo.class),
+ Mockito.any(ServiceRequestResult.class),
+ Mockito.eq(LineageWeatherManager.RequestStatus.COMPLETED));
+
+ provider.setServiceClient(client);
+
+ final RequestInfo requestInfo
+ = buildMockdRequestInfo(RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ);
+
+ Mockito.reset(getService().getCallTracker());
+ provider.processCityNameLookupRequest(requestInfo);
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+ request.fail();
+ }
+ });
+
+ Mockito.reset(getService().getCallTracker());
+ provider.processCityNameLookupRequest(requestInfo);
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+ request.reject(LineageWeatherManager.RequestStatus.SUBMITTED_TOO_SOON);
+ }
+ });
+
+ Mockito.reset(getService().getCallTracker());
+ provider.processCityNameLookupRequest(requestInfo);
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ ArgumentCaptor<ServiceRequest> params
+ = ArgumentCaptor.forClass(ServiceRequest.class);
+
+ Mockito.verify(getService().getCallTracker(), Mockito.timeout(TIMEOUT).times(1))
+ .onRequestSubmitted(params.capture());
+
+ ServiceRequest request = params.getValue();
+
+ List<WeatherLocation> locations = new ArrayList<>();
+ locations.add(new WeatherLocation.Builder(CITY_NAME).build());
+ ServiceRequestResult result = new ServiceRequestResult.Builder(locations).build();
+ request.complete(result);
+ }
+ });
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+
+ }
+
+ private RequestInfo buildMockdRequestInfo(int requestType) {
+ try {
+ Constructor<RequestInfo> c = RequestInfo.class.getDeclaredConstructor();
+ c.setAccessible(true);
+ RequestInfo info = c.newInstance();
+ Field type;
+ type = info.getClass().getDeclaredField("mRequestType");
+ type.setAccessible(true);
+ type.set(info, requestType);
+ switch (requestType) {
+ case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ:
+ Field cityName;
+ cityName = info.getClass().getDeclaredField("mCityName");
+ cityName.setAccessible(true);
+ cityName.set(info, CITY_NAME);
+ break;
+ case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
+ Field weatherLocation;
+ weatherLocation = info.getClass().getDeclaredField("mWeatherLocation");
+ weatherLocation.setAccessible(true);
+ weatherLocation.set(info, new WeatherLocation.Builder(CITY_NAME).build());
+ break;
+ case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ:
+ Field location;
+ location = info.getClass().getDeclaredField("mLocation");
+ location.setAccessible(true);
+ location.set(info, new Location("dummy_location_provider"));
+ break;
+ default:
+ throw new AssertionError("Unknown request type");
+ }
+ return info;
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+}