diff options
author | Michael W <baddaemon87@gmail.com> | 2019-01-06 19:36:00 +0100 |
---|---|---|
committer | Michael W <baddaemon87@gmail.com> | 2019-01-06 19:36:06 +0100 |
commit | 034c3c79dc788173929492f98ae36d1c78269c9c (patch) | |
tree | c0d8728b28efce880a2193da0bffdb1bcf286fdd | |
parent | 915e52eda2602558843fa5355861e79e993c65d9 (diff) | |
download | lineage-sdk-034c3c79dc788173929492f98ae36d1c78269c9c.tar.gz lineage-sdk-034c3c79dc788173929492f98ae36d1c78269c9c.tar.bz2 lineage-sdk-034c3c79dc788173929492f98ae36d1c78269c9c.zip |
Revert "Automatic translation import"
This reverts commit 5f06011a755307465238b04a6ce933472a7d9321.
Change-Id: I1b951cb63fd0b6628d87243a068ab4c083075f5a
70 files changed, 6450 insertions, 245 deletions
diff --git a/lineage/res/res/values-ar/strings.xml b/lineage/res/res/values-ar/strings.xml index d4bb25be..180b5c33 100644 --- a/lineage/res/res/values-ar/strings.xml +++ b/lineage/res/res/values-ar/strings.xml @@ -18,28 +18,20 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Label for the LineageOS system components when they are shown to the user. --> - <string name="lineageos_system_label">نظام LineageOS</string> <!-- Labels for the MODIFY_PROFILES permission. --> <string name="permlab_modifyProfiles">تعديل الملفات التعريفية للنظام</string> <string name="permdesc_modifyProfiles">السماح للتطبيق بتعديل الملفات التعريفية للنظام.</string> <!-- Labels for the HARDWARE_ABSTRACTION_ACCESS permission. --> <string name="permlab_useHardwareFramework">استخدام إطار عمل الجهاز</string> - <string name="permdesc_useHardwareFramework">السماح لأي تطبيق بالدخول إلى مكونات أجهزة النظام.</string> <!-- Labels for the WRITE_SETTINGS permission --> - <string name="permlab_writeSettings">تعديل اعدادات نظام Lineage</string> - <string name="permdesc_writeSettings">السماح لأي تطبيق بتعديل إعدادات نظام Lineage.</string> <!-- Labels for the WRITE_SECURE_SETTINGS permission --> - <string name="permlab_writeSecureSettings">تعديل تأمين اعدادات نظام Lineage</string> - <string name="permdesc_writeSecureSettings">للسماح لأي تطبيق بتعديل إعدادات أمان نظام Lineage. لا تستخدم التطبيقات العادية.</string> <!-- Labels for the PROTECTED_APP permission. --> <string name="permlab_protectedApp">إضافة وإزالة تطبيقات إلى التطبيقات المحمية</string> <string name="permdesc_protectedApp">يسمح للتطبيق بوضع علامة على تطبيقات أخرى كمحمية مع قفلها.</string> <!-- Labels for CHANGE_STYLE permission --> - <string name="permlab_changeStyle">تغيير شكل النظام</string> <!-- this is wrong, but google's package manager uses the android:description attribute as description for the runtime permission request dialog with non-default dangerous permissions --> - <string name="permdesc_changeStyle">تخصيص الوان النظام</string> <!-- Profiles --> <!-- Names of default profiles. --> <string name="profileNameDefault">افتراضي</string> @@ -63,11 +55,6 @@ <string name="perf_profile_bias_power">الكفاءة</string> <string name="perf_profile_bias_perf">سريع</string> <!-- Performance profiles --> - <string name="perf_profile_pwrsv_summary">الحد الأقصى لتوفير الطاقة، يقلل من أداء الجهاز</string> - <string name="perf_profile_bal_summary">التوازن بين الأداء الأمثل وخصائص الطاقة</string> - <string name="perf_profile_perf_summary">وضع الأداء العالي. مفيد للتطبيقات التي تتطلب زمن تأخير منخفض وإنتاجية أعلى وذلك عندما يكون استهلاك الطاقة ليس بمصدر قلق</string> - <string name="perf_profile_bias_power_summary">تفضيل حفظ الطاقة. يحدد الحد الأقصى من الطاقة لوحدة المعالجة المركزية و تحسين التوفير على حساب زمن التأخير العالي</string> - <string name="perf_profile_bias_perf_summary">تفضيل الأداء. تقليل زمن التأخير وزيادة استهلاك الطاقة بشكل طفيف</string> <!-- LiveDisplay strings --> <string name="live_display_auto">تلقائي</string> <string name="live_display_auto_summary">ضبط درجة الحرارة اللونية للشاشة تلقائياً بعد غروب الشمس وشروق الشمس</string> @@ -118,54 +105,18 @@ <string name="permlab_observe_audio_sessions">ملاحظة تغييرات جلسة عمل الصوت</string> <string name="permdesc_observe_audio_sessions">يسمح لتطبيق معين لملاحظة تدفقات الصوت الجاري إنشاؤها وتدميرها.</string> <!-- Privacy Guard --> - <string name="privacy_guard_manager_title">حارس الخصوصية</string> <!-- Permissions used by remote preferences --> - <string name="permlab_manageRemotePrefs">إعدادات التحكم عن بعد</string> - <string name="permdesc_manageRemotePrefs">السماح للتطبيق بإدارة الإعدادات عن بعد</string> <!-- About device screen, build date --> - <string name="build_date">تاريخ الإنشاء</string> <!-- About device screen, LineageOS API Level --> - <string name="lineage_api_level">مستوى LineageOS API</string> <!-- About device screen, LineageOS updates --> - <string name="lineage_updates">تحديثات LineageOS</string> <!-- About device screen, LineageOS version --> - <string name="lineage_version">إصدار LineageOS</string> <!-- About device screen, vendor security patch --> - <string name="lineage_vendor_security_patch">مستوى رمز تصحيح أمان المورد</string> <!-- General purpose use "unknown" string --> - <string name="unknown">غير معروف</string> <!-- Long-press back kill application --> - <string name="app_killed_message">تم إنهاء التطبيق</string> <!-- Status bar network traffic monitor strings --> - <string name="kilobitspersecond_short">kb/s</string> - <string name="megabitspersecond_short">Mb/s</string> - <string name="kilobytespersecond_short">kB/s</string> - <string name="megabytespersecond_short">MB/s</string> <!-- Accent colors --> - <string name="accent_black">الكربون</string> - <string name="accent_blue">توت ازرق</string> - <string name="accent_brown">الكاكاو</string> - <string name="accent_cyan">سماوي</string> - <string name="accent_green">الغابة</string> - <string name="accent_orange">يقطين</string> - <string name="accent_pink">كرز</string> - <string name="accent_purple">خزامي</string> - <string name="accent_red">طماطم</string> - <string name="accent_yellow">الموز</string> <!-- Trust interface --> <!-- This string will be referenced from other apps when they're referring to the Trust interface. Trust is a feature name, it's not suggested to translate this unless there are conflicts due to a different meaning of the word "trust" in your language --> - <string name="trust_feature_name">الائتمان</string> - <string name="permlab_trustInterface">الوصول إلى واجهة الائتمان</string> - <string name="permdesc_trustInterface">السماح لأحد التطبيقات بعرض تحذيرات واقتراحات الائتمان</string> - <string name="trust_notification_channel">تحذيرات الائتمان</string> - <string name="trust_notification_title_security">ائتمان حماية النظام</string> - <string name="trust_notification_content_selinux">SELinux ليس فرض، تم إضعاف الأمان الخاص بك</string> - <string name="trust_notification_title_root">ائتمان الوصول الى الروت</string> - <string name="trust_notification_content_root">يستخدم أحد التطبيقات امتيازات الجذر في الوقت الحالي</string> - <string name="trust_notification_content_keys">تم توقيع هذا الإصدار باستخدام مفاتيح عامة</string> - <string name="trust_notification_title_onboarding">اكتشف الائتمان</string> - <string name="trust_notification_content_onboarding">تعرف على كيفية التأكد من سلامة جهازك</string> - <string name="trust_notification_action_manage">إدارة التنبيهات</string> </resources> diff --git a/lineage/res/res/values-ast-rES/strings.xml b/lineage/res/res/values-ast-rES/strings.xml index 9fce7cfc..924d0325 100644 --- a/lineage/res/res/values-ast-rES/strings.xml +++ b/lineage/res/res/values-ast-rES/strings.xml @@ -18,34 +18,24 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Label for the LineageOS system components when they are shown to the user. --> - <string name="lineageos_system_label">Sistema LineageOS</string> <!-- Labels for the MODIFY_PROFILES permission. --> <string name="permlab_modifyProfiles">modificar perfiles del sistema</string> <string name="permdesc_modifyProfiles">Permite qu\'una aplicación modifique los perfiles del sistema.</string> <!-- Labels for the HARDWARE_ABSTRACTION_ACCESS permission. --> <string name="permlab_useHardwareFramework">usar framework de hardware</string> - <string name="permdesc_useHardwareFramework">Permite qu\'una aplicación acceda al framework de hardware de LineageOS.</string> <!-- Labels for the WRITE_SETTINGS permission --> - <string name="permlab_writeSettings">modificar la configuración del sistema de Lineage</string> - <string name="permdesc_writeSettings">Permite qu\'una aplicación modifique los axustes del sistema de Lineage.</string> <!-- Labels for the WRITE_SECURE_SETTINGS permission --> - <string name="permlab_writeSecureSettings">modificar la configuración segura del sistema de Lineage</string> - <string name="permdesc_writeSecureSettings">Permite qu\'una aplicación modifique la configuración segura del sistema de Lineage. Nun s\'usa pa les aplicaciones normales.</string> <!-- Labels for the PROTECTED_APP permission. --> - <string name="permlab_protectedApp">amestar y desaniciar aplicaciones p\'aplicaciones protexíes</string> <string name="permdesc_protectedApp">Permite qu\'una aplicación conseñe a otres como protexíes y blóquiales.</string> <!-- Labels for CHANGE_STYLE permission --> - <string name="permlab_changeStyle">camudar l\'estilu del sistema</string> <!-- this is wrong, but google's package manager uses the android:description attribute as description for the runtime permission request dialog with non-default dangerous permissions --> - <string name="permdesc_changeStyle">personalizar los colores del sistema</string> <!-- Profiles --> <!-- Names of default profiles. --> <string name="profileNameDefault">Por defeutu</string> <string name="profileNameWork">Trabayu</string> <string name="profileNameHome">Home</string> - <string name="profileNameSilent">Silenciu</string> <string name="profileNameNight">Nueche</string> <string name="profileNameAutomobile">Automóvil</string> <!-- Names of application groups. --> @@ -55,13 +45,11 @@ <string name="profileGroupEmail">Corréu</string> <string name="profileGroupSMS">SMS</string> <!-- Name of wildcard profile. --> - <string name="wildcardProfile">Otru</string> <!-- Performance profiles --> <string name="perf_profile_pwrsv">Aforru d\'enerxía</string> <string name="perf_profile_bal">Balanceáu</string> <string name="perf_profile_perf">Rindimientu</string> <string name="perf_profile_bias_power">Eficiencia</string> - <string name="perf_profile_bias_perf">Rápidu</string> <!-- Performance profiles --> <string name="perf_profile_pwrsv_summary">Aforros máximos d\'enerxía, amenorga\'l rindimientu del preséu</string> <string name="perf_profile_bal_summary">Equilibriu de rindimientu óptimu y carauterístiques d\'enerxía</string> @@ -69,7 +57,6 @@ <string name="perf_profile_bias_power_summary">Favorez los aforros d\'enerxía. Llenda la potencia máximo de la CPU y optimízala pa un aforru d\'enerxía empara d\'una llatencia mayor</string> <string name="perf_profile_bias_perf_summary">Favorez el rindimientu. Amenorga la llatencia con un consumu d\'enerxía llixeramente aumentáu</string> <!-- LiveDisplay strings --> - <string name="live_display_auto">Automáticu</string> <string name="live_display_auto_summary">Axusta automáticamente la temperatura de color de la pantalla dempués del tapecer y l\'aséu</string> <string name="live_display_off">Non</string> <string name="live_display_off_summary">Deshabilita tolos axustes</string> @@ -77,15 +64,12 @@ <string name="live_display_day_summary">Usa namái los axustes de día</string> <string name="live_display_night">Nueche</string> <string name="live_display_night_summary">Usa namái los axustes de nueche</string> - <string name="live_display_outdoor">Esterior (lluz solar)</string> <string name="live_display_outdoor_summary">Usa namái los axustes d\'esteriores</string> <string name="live_display_hint">LiveDisplay pue ayudar a amenorgar el cansanciu de güeyos y ayudate a dormir pela nueche. ¡Primi equí pa probalu!</string> - <string name="accessibility_quick_settings_live_display_off">LiveDisplay desactiváu.</string> <string name="accessibility_quick_settings_live_display_auto">LiveDisplay: mou auto.</string> <string name="accessibility_quick_settings_live_display_day">LiveDisplay: mou diurnu.</string> <string name="accessibility_quick_settings_live_display_night">LiveDisplay: mou nocherniegu.</string> <string name="accessibility_quick_settings_live_display_outdoor">LiveDisplay: mou esterior.</string> - <string name="accessibility_quick_settings_live_display_changed_off">LiveDisplay desactiváu.</string> <string name="accessibility_quick_settings_live_display_changed_auto">LiveDisplay camudó al mou auto.</string> <string name="accessibility_quick_settings_live_display_changed_day">LiveDisplay camudó al mou diurnu.</string> <string name="accessibility_quick_settings_live_display_changed_night">LiveDisplay camudó al mou nocherniegu.</string> @@ -95,14 +79,6 @@ <!-- Performance manager permission description --> <string name="permdesc_perfAccessDesc">Permite qu\'una aplicación acceda al serviciu de rindimientu. Enxamás debería precisase p\'aplicaciones normales.</string> <!-- Weather Service strings --> - <string name="permlab_weather_read">lleer la metereoloxía</string> - <string name="permdesc_weather_read">Permite qu\'una aplicación llea\'l conteníu del fornidor meteorolóxicu.</string> - <string name="permlab_weather_write">anovar el fornidor meteorolóxicu</string> - <string name="permdesc_weather_write">Permite qu\'una aplicación anueve\'l conteníu del fornidor meteorolóxicu.</string> - <string name="permlab_weather_bind">arreyar como serviciu fornidor de metereoloxía</string> - <string name="permdesc_weather_bind">Permite qu\'una aplicación s\'identifique como un serviciu fornidor de meteoroloxía.</string> - <string name="permlab_weather_access_mgr">acceder al serviciu de metereoloxía</string> - <string name="permdesc_weather_access_mgr">Permite qu\'una aplicación acceda al serviciu meteorolóxicu nel sistema. Enxamás debería precisase p\'aplicaciones normales.</string> <!-- DataUsageProvider write permission title --> <string name="permlab_dataUsageWrite">modificar base de datos d\'usu de datos</string> <!-- DataUsageProvider write permission description --> @@ -123,49 +99,16 @@ <string name="permlab_manageRemotePrefs">xestionar axustes remotos</string> <string name="permdesc_manageRemotePrefs">Permite qu\'una aplicación xestione axustes remotos</string> <!-- About device screen, build date --> - <string name="build_date">Data de la compilación</string> <!-- About device screen, LineageOS API Level --> - <string name="lineage_api_level">Nivel de l\'API de LineageOS</string> <!-- About device screen, LineageOS updates --> - <string name="lineage_updates">Anovamientos de LineageOS</string> <!-- About device screen, LineageOS version --> - <string name="lineage_version">Versión de LineageOS</string> <!-- About device screen, vendor security patch --> - <string name="lineage_vendor_security_patch">Nivel de parche de seguridá del fornidor</string> <!-- General purpose use "unknown" string --> - <string name="unknown">Desconozse</string> <!-- Long-press back kill application --> - <string name="app_killed_message">Aplicación matada</string> <!-- Status bar network traffic monitor strings --> - <string name="kilobitspersecond_short">kb/s</string> - <string name="megabitspersecond_short">Mb/s</string> - <string name="kilobytespersecond_short">kB/s</string> - <string name="megabytespersecond_short">MB/s</string> <!-- Accent colors --> - <string name="accent_black">Carbón</string> - <string name="accent_blue">Arándanu</string> - <string name="accent_brown">Cacáu</string> - <string name="accent_cyan">Cianu</string> - <string name="accent_green">Viesca</string> - <string name="accent_orange">Calabaza</string> - <string name="accent_pink">Zreza</string> - <string name="accent_purple">Llavanda</string> - <string name="accent_red">Tomate</string> - <string name="accent_yellow">Plátanu</string> <!-- Trust interface --> <!-- This string will be referenced from other apps when they're referring to the Trust interface. Trust is a feature name, it's not suggested to translate this unless there are conflicts due to a different meaning of the word "trust" in your language --> - <string name="trust_feature_name">Trust</string> - <string name="permlab_trustInterface">acceder a interface Trust</string> - <string name="permdesc_trustInterface">Permite qu\'una aplicación amuese avisos y suxerencies Trust</string> - <string name="trust_notification_channel">Alertes Trust</string> - <string name="trust_notification_title_security">Trust \u2022 Seguridá del sistema</string> - <string name="trust_notification_content_selinux">SELinux nun se ta aplicando, la seguranza ye reducida</string> - <string name="trust_notification_title_root">Trust \u2022 Accesu root</string> - <string name="trust_notification_content_root">Una aplicación ta usando los privilexos root nesti momentu</string> - <string name="trust_notification_content_keys">Esta compilación asignóse con claves públiques</string> - <string name="trust_notification_title_onboarding">Descubri Trust</string> - <string name="trust_notification_content_onboarding">Conoz como caltener seguru el dispositivu</string> - <string name="trust_notification_action_manage">Xestionar alertes</string> </resources> diff --git a/lineage/res/res/values-cy/strings.xml b/lineage/res/res/values-cy/strings.xml index 2bf2cd4b..86c07d1b 100644 --- a/lineage/res/res/values-cy/strings.xml +++ b/lineage/res/res/values-cy/strings.xml @@ -18,50 +18,22 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Label for the LineageOS system components when they are shown to the user. --> - <string name="lineageos_system_label">System LineageOS</string> <!-- Labels for the MODIFY_PROFILES permission. --> - <string name="permlab_modifyProfiles">addasu proffiliau system</string> - <string name="permdesc_modifyProfiles">Mae\'n caniatáu i ap addasu proffiliau system.</string> <!-- Labels for the HARDWARE_ABSTRACTION_ACCESS permission. --> <string name="permlab_useHardwareFramework">defnyddio fframwaith caledwedd</string> - <string name="permdesc_useHardwareFramework">Mae\'n caniatáu i ap gyrchu fframwaith caledwedd Lineage.</string> <!-- Labels for the WRITE_SETTINGS permission --> - <string name="permlab_writeSettings">addasu gosodiadau system Lineage</string> - <string name="permdesc_writeSettings">Mae\'n caniatáu i ap addasu gosodiadau system LineageOS.</string> <!-- Labels for the WRITE_SECURE_SETTINGS permission --> - <string name="permlab_writeSecureSettings">addasu gosodiadau system ddiogel Lineage</string> - <string name="permdesc_writeSecureSettings">Mae\'n caniatáu i ap addasu gosodiadau system ddiogel LineageOS. Dim i\'w ddefnyddio gan apiau arferol.</string> <!-- Labels for the PROTECTED_APP permission. --> - <string name="permlab_protectedApp">ychwanegu a thynnu apiau i warchod apiau</string> - <string name="permdesc_protectedApp">Mae\'n caniatáu i ap nodi apiau eraill fel wedi eu diogelu ac i\'w cloi nhw.</string> <!-- Labels for CHANGE_STYLE permission --> - <string name="permlab_changeStyle">newid arddull system</string> <!-- this is wrong, but google's package manager uses the android:description attribute as description for the runtime permission request dialog with non-default dangerous permissions --> - <string name="permdesc_changeStyle">addasu lliwiau\'r system</string> <!-- Profiles --> <!-- Names of default profiles. --> - <string name="profileNameDefault">Rhagosodiad</string> <string name="profileNameWork">Gwaith</string> - <string name="profileNameHome">Cartref</string> - <string name="profileNameSilent">Distaw</string> - <string name="profileNameNight">Nos</string> - <string name="profileNameAutomobile">Cerbyd</string> <!-- Names of application groups. --> - <string name="profileGroupPhone">Ffôn</string> - <string name="profileGroupCalendar">Calendr</string> - <string name="profileGroupGmail">Gmail</string> - <string name="profileGroupEmail">Ebost</string> - <string name="profileGroupSMS">SMS</string> <!-- Name of wildcard profile. --> - <string name="wildcardProfile">Arall</string> <!-- Performance profiles --> - <string name="perf_profile_pwrsv">Arbed pŵer</string> - <string name="perf_profile_bal">Cytbwys</string> - <string name="perf_profile_perf">Perfformiad</string> - <string name="perf_profile_bias_power">Effeithlonrwydd</string> - <string name="perf_profile_bias_perf">Cyflym</string> <!-- Performance profiles --> <string name="perf_profile_pwrsv_summary">Arbedion pŵer gorau, gan leihau perfformiad y ddyfais.</string> <string name="perf_profile_bal_summary">Cydbwysedd o berfformiad optimaidd a nodweddion pŵer.</string> @@ -69,54 +41,19 @@ <string name="perf_profile_bias_power_summary">Ffafrio arbedion pŵer. Mae hyn yn cyfyngu pŵer y prosesydd ac yn ei optimeiddio ar gyfer arbed defnydd pŵer ar draul cuddni uwch.</string> <string name="perf_profile_bias_perf_summary">Ffafrio perfformiad da. Mae\'n lleihau cuddni gyda defnydd pŵer uwch.</string> <!-- LiveDisplay strings --> - <string name="live_display_auto">Awtomatig</string> - <string name="live_display_auto_summary">Addasu tymheredd lliw\'r sgrin yn awtomatig ar ôl machlud a gwawr</string> - <string name="live_display_off">I ffwrdd</string> - <string name="live_display_off_summary">Analluogi pob addasiad</string> - <string name="live_display_day">Dydd</string> <string name="live_display_day_summary">Defnyddio gosodiadau dydd yn unig</string> - <string name="live_display_night">Nos</string> <string name="live_display_night_summary">Defnyddio gosodiadau nos yn unig</string> - <string name="live_display_outdoor">Awyr agored (heulwen)</string> <string name="live_display_outdoor_summary">Defnyddio gosodiadau awyr agored yn unig</string> - <string name="live_display_hint">Gall LiveDisplay helpu lleihau straen ar y llygaid a dy helpu i gysgu gyda\'r nos. Clicia yma i roi cynnig arno!</string> - <string name="accessibility_quick_settings_live_display_off">LiveDisplay i ffwrdd.</string> - <string name="accessibility_quick_settings_live_display_auto">LiveDisplay: modd awtomatig.</string> - <string name="accessibility_quick_settings_live_display_day">LiveDisplay: modd dydd.</string> - <string name="accessibility_quick_settings_live_display_night">LiveDisplay: modd nos.</string> - <string name="accessibility_quick_settings_live_display_outdoor">LiveDisplay: modd awyr agored.</string> - <string name="accessibility_quick_settings_live_display_changed_off">LiveDisplay wedi\'i droi i ffwrdd.</string> - <string name="accessibility_quick_settings_live_display_changed_auto">LiveDisplay wedi\'i newid i fodd awtomatig.</string> - <string name="accessibility_quick_settings_live_display_changed_day">LiveDisplay wedi\'i newid i fodd dydd.</string> - <string name="accessibility_quick_settings_live_display_changed_night">LiveDisplay wedi\'i newid i fodd nos.</string> - <string name="accessibility_quick_settings_live_display_changed_outdoor">LiveDisplay wedi\'i newid i fodd awyr agored.</string> <!-- Performance manager permission title --> - <string name="permlab_perfAccess">mynediad at reolwr perfformiad</string> <!-- Performance manager permission description --> - <string name="permdesc_perfAccessDesc">Mae\'n caniatáu i ap gyrchu\'r gwasanaeth perfformiad. Ni ddylai apiau arferol byth fod ei angen.</string> <!-- Weather Service strings --> - <string name="permlab_weather_read">darllen y tywydd</string> - <string name="permdesc_weather_read">Mae\'n caniatáu i ap ddarllen cynnwys gan y darparydd tywydd.</string> <string name="permlab_weather_write">diweddaru darparwr tywydd</string> - <string name="permdesc_weather_write">Mae\'n caniatáu i ap ddiweddaru cynnwys y darparydd tywydd.</string> - <string name="permlab_weather_bind">clymu fel gwasanaeth darparu tywydd</string> - <string name="permdesc_weather_bind">Mae\'n galluogi ap i gael ei adnabod fel gwasanaeth darparu tywydd.</string> - <string name="permlab_weather_access_mgr">mynediad at wasanaeth tywydd</string> - <string name="permdesc_weather_access_mgr">Mae\'n caniatáu i ap gyrchu\'r gwasanaeth tywydd yn y system. Ni ddylai apiau arferol byth fod ei angen.</string> <!-- DataUsageProvider write permission title --> - <string name="permlab_dataUsageWrite">addasu\'r gronfa ddata defnydd data</string> <!-- DataUsageProvider write permission description --> - <string name="permdesc_dataUsageWrite">Mae\'n caniatáu i ap ddiweddaru cynnwys y gronfa ddata defnydd data.</string> <!-- DataUsageProvider read permission title --> - <string name="permlab_dataUsageRead">darllen cronfa ddata defnydd data</string> <!-- DataUsageProvider read permission description --> - <string name="permdesc_dataUsageRead">Mae\'n caniatáu i ap ddarllen cynnwys y gronfa ddata defnydd data.</string> <!-- LiveDisplay manager permission --> - <string name="permlab_manageLiveDisplay">rheoli gosodiadau LiveDisplay</string> - <string name="permdesc_manageLiveDisplay">Mae\'n caniatáu i ap ffurfweddu gosodiadau dangosydd uwch.</string> <!-- LineageAudioService - observe session changes permission --> - <string name="permlab_observe_audio_sessions">gwylio newidiadau sesiynau sain</string> - <string name="permdesc_observe_audio_sessions">Mae\'n caniatáu i ap wylio ffrydiau sain yn cael eu creu a\'u dinistrio.</string> <!-- Privacy Guard --> <string name="privacy_guard_manager_title">Gwarchodydd Preifatrwydd</string> <!-- Permissions used by remote preferences --> @@ -125,37 +62,17 @@ <!-- About device screen, build date --> <string name="build_date">Dyddiad adeiledd</string> <!-- About device screen, LineageOS API Level --> - <string name="lineage_api_level">Lefel API LineageOS</string> <!-- About device screen, LineageOS updates --> - <string name="lineage_updates">Diweddariadau LineageOS</string> <!-- About device screen, LineageOS version --> - <string name="lineage_version">Fersiwn LineageOS</string> <!-- About device screen, vendor security patch --> - <string name="lineage_vendor_security_patch">Lefel patsh diogelwch gwneuthurwr</string> <!-- General purpose use "unknown" string --> <string name="unknown">Anhysybys</string> <!-- Long-press back kill application --> - <string name="app_killed_message">Lladdwyd yr ap</string> <!-- Status bar network traffic monitor strings --> - <string name="kilobitspersecond_short">kb/e</string> - <string name="megabitspersecond_short">Mb/e</string> - <string name="kilobytespersecond_short">kB/e</string> - <string name="megabytespersecond_short">MB/e</string> <!-- Accent colors --> - <string name="accent_black">Carbon</string> - <string name="accent_blue">Llusen</string> - <string name="accent_brown">Coco</string> - <string name="accent_cyan">Gwyrddlas</string> - <string name="accent_green">Pys</string> - <string name="accent_orange">Moron</string> - <string name="accent_pink">Mafon</string> - <string name="accent_purple">Betys</string> <string name="accent_red">Tomato</string> - <string name="accent_yellow">Cennin Pedr</string> <!-- Trust interface --> <!-- This string will be referenced from other apps when they're referring to the Trust interface. Trust is a feature name, it's not suggested to translate this unless there are conflicts due to a different meaning of the word "trust" in your language --> - <string name="permdesc_trustInterface">Mae\'n caniatáu i ap ddangos rhybuddion ac awgrymiadau Trust.</string> - <string name="trust_notification_content_selinux">Dyw SELinux ddim yn gorfodi. Mae dy ddiogelwch wedi\'i wanhau.</string> </resources> diff --git a/lineage/res/res/values-sc-rIT/strings.xml b/lineage/res/res/values-sc-rIT/strings.xml index d6e69035..9f84b86b 100644 --- a/lineage/res/res/values-sc-rIT/strings.xml +++ b/lineage/res/res/values-sc-rIT/strings.xml @@ -18,14 +18,9 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Label for the LineageOS system components when they are shown to the user. --> - <string name="lineageos_system_label">Sistema LineageOS</string> <!-- Labels for the MODIFY_PROFILES permission. --> - <string name="permlab_modifyProfiles">modìfica sos profilos de sistema</string> - <string name="permdesc_modifyProfiles">Permitit a un\'aplicatzione de modificare sos profilos de sistema.</string> <!-- Labels for the HARDWARE_ABSTRACTION_ACCESS permission. --> <!-- Labels for the WRITE_SETTINGS permission --> - <string name="permlab_writeSettings">modìfica sas impostatziones de sistema de Lineage</string> - <string name="permdesc_writeSettings">Permitit a un\'aplicatzione de modificare sas impostatziones de sistema de Lineage.</string> <!-- Labels for the WRITE_SECURE_SETTINGS permission --> <!-- Labels for the PROTECTED_APP permission. --> <!-- Labels for CHANGE_STYLE permission --> @@ -43,8 +38,6 @@ <!-- Names of application groups. --> <string name="profileGroupPhone">Telèfonu</string> <string name="profileGroupCalendar">Calendàriu</string> - <string name="profileGroupGmail">Gmail</string> - <string name="profileGroupSMS">SMS</string> <!-- Name of wildcard profile. --> <string name="wildcardProfile">Àteru</string> <!-- Performance profiles --> @@ -83,7 +76,6 @@ <!-- Permissions used by remote preferences --> <!-- About device screen, build date --> <!-- About device screen, LineageOS API Level --> - <string name="lineage_api_level">Livellu de s\'API de LineageOS</string> <!-- About device screen, LineageOS updates --> <!-- About device screen, LineageOS version --> <!-- About device screen, vendor security patch --> @@ -93,7 +85,6 @@ <!-- Status bar network traffic monitor strings --> <!-- Accent colors --> <string name="accent_cyan">Asulu</string> - <string name="accent_yellow">Banana</string> <!-- Trust interface --> <!-- This string will be referenced from other apps when they're referring to the Trust interface. Trust is a feature name, it's not suggested to translate this unless there are conflicts due diff --git a/packages/LineageSettingsProvider/res/values-ar/strings.xml b/packages/LineageSettingsProvider/res/values-ar/strings.xml index 233a8314..0647eaf6 100644 --- a/packages/LineageSettingsProvider/res/values-ar/strings.xml +++ b/packages/LineageSettingsProvider/res/values-ar/strings.xml @@ -15,6 +15,4 @@ See the License for the specific language governing permissions and limitations under the License. --> -<resources> - <string name="app_name">اعدادت تخزين Lineage</string> -</resources> +<resources></resources> diff --git a/packages/LineageSettingsProvider/res/values-cy/strings.xml b/packages/LineageSettingsProvider/res/values-cy/strings.xml index ef925ae2..0647eaf6 100644 --- a/packages/LineageSettingsProvider/res/values-cy/strings.xml +++ b/packages/LineageSettingsProvider/res/values-cy/strings.xml @@ -15,6 +15,4 @@ See the License for the specific language governing permissions and limitations under the License. --> -<resources> - <string name="app_name">Storfa Gosodiadau Lineage</string> -</resources> +<resources></resources> diff --git a/packages/LineageSettingsProvider/res/values-sc-rIT/strings.xml b/packages/LineageSettingsProvider/res/values-sc-rIT/strings.xml index 4b7acd94..0647eaf6 100644 --- a/packages/LineageSettingsProvider/res/values-sc-rIT/strings.xml +++ b/packages/LineageSettingsProvider/res/values-sc-rIT/strings.xml @@ -15,6 +15,4 @@ See the License for the specific language governing permissions and limitations under the License. --> -<resources> - <string name="app_name">Archìviu de impostatziones de Lineage</string> -</resources> +<resources></resources> diff --git a/packages/LineageSettingsProvider/tests/Android.mk b/packages/LineageSettingsProvider/tests/Android.mk new file mode 100644 index 00000000..31c3aa38 --- /dev/null +++ b/packages/LineageSettingsProvider/tests/Android.mk @@ -0,0 +1,56 @@ +# +# 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. +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_PACKAGE_NAME := LineageSettingsProviderTests +LOCAL_INSTRUMENTATION_FOR := LineageSettingsProvider + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_PROGUARD_ENABLED := optimization shrinktests +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_STATIC_JAVA_LIBRARIES := \ + org.lineageos.platform.internal + +include $(BUILD_PACKAGE) + +# Register as LineageTS +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_PACKAGE_NAME := CmtsLineageSettingsProviderTests +LOCAL_INSTRUMENTATION_FOR := LineageSettingsProvider + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_PROGUARD_ENABLED := optimization shrinktests +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_STATIC_JAVA_LIBRARIES := \ + org.lineageos.platform.internal + +include $(BUILD_LineageTS_PACKAGE) + diff --git a/packages/LineageSettingsProvider/tests/AndroidManifest.xml b/packages/LineageSettingsProvider/tests/AndroidManifest.xml new file mode 100644 index 00000000..ec333a69 --- /dev/null +++ b/packages/LineageSettingsProvider/tests/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.lineageos.lineagesettings.tests"> + + <uses-permission android:name="lineageos.permission.WRITE_SETTINGS"/> + <uses-permission android:name="lineageos.permission.WRITE_SECURE_SETTINGS"/> + <uses-permission android:name="android.permission.WRITE_SETTINGS"/> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.MANAGE_USERS" /> + + <instrumentation + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="org.lineageos.lineagesettings.tests" + android:label="Lineage Settings Provider Tests" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> +</manifest> diff --git a/packages/LineageSettingsProvider/tests/README.md b/packages/LineageSettingsProvider/tests/README.md new file mode 100644 index 00000000..5b91285e --- /dev/null +++ b/packages/LineageSettingsProvider/tests/README.md @@ -0,0 +1,7 @@ +## Lineage Settings Provider Tests +The tests package contains coverage for the Lineage Settings provider as well as +its public interfaces. + +To run the tests (on a live device): + + ```adb shell am instrument -w org.lineageos.lineagesettings.tests/android.test.InstrumentationTestRunner``` diff --git a/packages/LineageSettingsProvider/tests/proguard.flags b/packages/LineageSettingsProvider/tests/proguard.flags new file mode 100644 index 00000000..d9e855cb --- /dev/null +++ b/packages/LineageSettingsProvider/tests/proguard.flags @@ -0,0 +1,50 @@ +# 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. + +# Don't skip non public library classes, make sure we're not keeping anything which will get mapped against api verification. +-dontskipnonpubliclibraryclasses + +# Do the same with class members +-dontskipnonpubliclibraryclassmembers + +# Keep test packages +-keep class android.support.** { *; } +-keep class android.test.** { *; } +-keep public class * extends android.support.** { *; } +-keep public class * extends android.test.** { *; } +-keep interface android.support.** { *; } +-keep interface android.test.** { *; } + +# Keep all junit classes +-keep class junit.** { *; } +-keep class org.junit.** { *; } +-keep interface junit.** { *; } +-keep interface org.junit.** { *; } + +# Keep compiled java classes from declared aidl's within the test package +-keep public class * extends android.os.IInterface { *; } + +# Don't warn about the Android Support Test JUnit Runner +-dontwarn android.support.** +-dontwarn android.test.** + +# Don't warn about junit +-dontwarn junit.** +-dontwarn org.junit.** + +# Always process +-forceprocessing + +# Make sure not to obfuscate the output +-dontobfuscate diff --git a/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsGlobalTests.java b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsGlobalTests.java new file mode 100644 index 00000000..619580bb --- /dev/null +++ b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsGlobalTests.java @@ -0,0 +1,126 @@ +/** + * 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.lineagesettings.tests; + +import android.content.ContentResolver; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.LineageSettings; + +public class LineageSettingsGlobalTests extends AndroidTestCase { + private ContentResolver mContentResolver; + + private static final String UNREALISTIC_SETTING = "_______UNREAL_______"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContentResolver = mContext.getContentResolver(); + } + + @SmallTest + public void testFloat() { + final float expectedFloatValue = 1.0f; + LineageSettings.Global.putFloat(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER, expectedFloatValue); + + try { + float actualValue = LineageSettings.Global.getFloat(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedFloatValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testFloatWithDefault() { + final float expectedDefaultFloatValue = 1.5f; + float actualValue = LineageSettings.Global.getFloat(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultFloatValue); + assertEquals(expectedDefaultFloatValue, actualValue); + } + + @SmallTest + public void testInt() { + final int expectedIntValue = 2; + LineageSettings.Global.putInt(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER, expectedIntValue); + + try { + int actualValue = LineageSettings.Global.getInt(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedIntValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testIntWithDefault() { + final int expectedDefaultIntValue = 11; + int actualValue = LineageSettings.Global.getInt(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultIntValue); + assertEquals(expectedDefaultIntValue, actualValue); + } + + @SmallTest + public void testLong() { + final long expectedLongValue = 3l; + LineageSettings.Global.putLong(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER, expectedLongValue); + + try { + long actualValue = LineageSettings.Global.getLong(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedLongValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testLongWithDefault() { + final long expectedDefaultLongValue = 17l; + long actualValue = LineageSettings.Global.getLong(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultLongValue); + assertEquals(expectedDefaultLongValue, actualValue); + } + + @SmallTest + public void testString() { + final String expectedStringValue = "4"; + LineageSettings.Global.putString(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER, expectedStringValue); + + String actualValue = LineageSettings.Global.getString(mContentResolver, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedStringValue, actualValue); + } + + @SmallTest + public void testGetUri() { + final Uri expectedUri = Uri.withAppendedPath(LineageSettings.Global.CONTENT_URI, + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + + final Uri actualUri = LineageSettings.Global.getUriFor( + LineageSettings.Global.__MAGICAL_TEST_PASSING_ENABLER); + + assertEquals(expectedUri, actualUri); + } +} diff --git a/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderDefaultsTest.java b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderDefaultsTest.java new file mode 100644 index 00000000..f5c7ba37 --- /dev/null +++ b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderDefaultsTest.java @@ -0,0 +1,272 @@ +/** + * 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.lineagesettings.tests; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.UserHandle; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.ArrayList; + +import android.text.TextUtils; +import android.util.Log; +import android.util.TypedValue; +import lineageos.providers.LineageSettings; +import org.lineageos.lineagesettings.LineageDatabaseHelper; +import org.lineageos.lineagesettings.LineageSettingsProvider; +import org.lineageos.lineagesettings.R; + +/** + * Created by adnan on 1/25/16. + */ +public class LineageSettingsProviderDefaultsTest extends AndroidTestCase { + private ContentResolver mContentResolver; + private boolean mHasMigratedSettings; + private Resources mRemoteResources; + + // These data structures are set up in a way that is easier for manual input of new defaults + private static ArrayList<Setting> SYSTEM_SETTINGS_DEFAULTS = new ArrayList<Setting>(); + private static ArrayList<Setting> SECURE_SETTINGS_DEFAULTS = new ArrayList<Setting>(); + private static ArrayList<Setting> GLOBAL_SETTINGS_DEFAULTS = new ArrayList<Setting>(); + + //SYSTEM + static { + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN, + "R.integer.def_qs_quick_pulldown")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL, + "R.integer.def_notification_brightness_level")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.ENABLE_FORWARD_LOOKUP, + "R.integer.def_forward_lookup")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.ENABLE_PEOPLE_LOOKUP, + "R.integer.def_people_lookup")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.ENABLE_REVERSE_LOOKUP, + "R.integer.def_reverse_lookup")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.SYSTEM_PROFILES_ENABLED, + "R.bool.def_profiles_enabled")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, + "R.bool.def_notification_pulse_custom_enable")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.SWAP_VOLUME_KEYS_ON_ROTATION, + "R.bool.def_swap_volume_keys_on_rotation")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES, + "R.string.def_notification_pulse_custom_value")); + SYSTEM_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.System.STATUS_BAR_BATTERY_STYLE, + "R.integer.def_battery_style")); + } + + //SECURE + static { + SECURE_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Secure.ADVANCED_MODE, + "R.bool.def_advanced_mode")); + SECURE_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Secure.QS_USE_MAIN_TILES, + "R.bool.def_sysui_qs_main_tiles")); + SECURE_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Secure.STATS_COLLECTION, + "R.bool.def_stats_collection")); + SECURE_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Secure.LOCKSCREEN_VISUALIZER_ENABLED, + "R.bool.def_lockscreen_visualizer")); + SECURE_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Secure.PROTECTED_COMPONENT_MANAGERS, + "R.string.def_protected_component_managers")); + } + + //GLOBAL + static { + GLOBAL_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Global.POWER_NOTIFICATIONS_ENABLED, + "R.bool.def_power_notifications_enabled")); + GLOBAL_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Global.POWER_NOTIFICATIONS_VIBRATE, + "R.bool.def_power_notifications_vibrate")); + GLOBAL_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Global.POWER_NOTIFICATIONS_RINGTONE, + "R.string.def_power_notifications_ringtone")); + GLOBAL_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Global.WEATHER_TEMPERATURE_UNIT, + "R.integer.def_temperature_unit")); + GLOBAL_SETTINGS_DEFAULTS.add(new Setting( + LineageSettings.Global.DEV_FORCE_SHOW_NAVBAR, + "R.integer.def_force_show_navbar")); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContentResolver = getContext().getContentResolver(); + mHasMigratedSettings = getContext().getSharedPreferences(LineageSettingsProvider.TAG, + Context.MODE_PRIVATE).getBoolean(LineageSettingsProvider.PREF_HAS_MIGRATED_LINEAGE_SETTINGS, + false); + mRemoteResources = getRemoteResources("org.lineageos.lineagesettings"); + } + + @SmallTest + public void testVerifySystemSettingsDefault() { + if (verifyNotMigratedSettings()) { + for (Setting setting : SYSTEM_SETTINGS_DEFAULTS) { + verifyDefaultSettingForTable(setting, LineageDatabaseHelper.LineageTableNames.TABLE_SYSTEM); + } + } + } + + @SmallTest + public void testVerifySecureSettingsDefaults() { + if (verifyNotMigratedSettings()) { + for (Setting setting : SECURE_SETTINGS_DEFAULTS) { + verifyDefaultSettingForTable(setting, LineageDatabaseHelper.LineageTableNames.TABLE_SECURE); + } + } + } + + @SmallTest + public void testVerifyGlobalSettingsDefaults() { + if (verifyNotMigratedSettings()) { + for (Setting setting : GLOBAL_SETTINGS_DEFAULTS) { + verifyDefaultSettingForTable(setting, LineageDatabaseHelper.LineageTableNames.TABLE_GLOBAL); + } + } + } + + private boolean verifyNotMigratedSettings() { + return !mHasMigratedSettings; + } + + private void verifyDefaultSettingForTable(Setting setting, String table) { + TypedValue value = new TypedValue(); + try { + int identifier = mRemoteResources.getIdentifier( + setting.mDefResName, setting.mType, "org.lineageos.lineagesettings"); + mRemoteResources.getValue(identifier, value, true); + } catch (Resources.NotFoundException e) { + // Resource not found, can't verify because it probably wasn't loaded in + throw new AssertionError("Unable to find resource for " + setting.mKey); + } + + try { + switch (value.type) { + case TypedValue.TYPE_INT_DEC: + int actualValue = getIntForTable(setting, table); + try { + assertEquals(value.data, actualValue); + } catch (AssertionError e) { + throw new AssertionError("Compared value of " + setting.mKey + " expected " + + value.data + " got " + actualValue); + } + break; + case TypedValue.TYPE_INT_BOOLEAN: + int actualBooleanValue = getIntForTable(setting, table); + try { + //This is gross + //Boolean can be "true" as long as it isn't 0 + if (value.data != 0) { + value.data = 1; + } + assertEquals(value.data, actualBooleanValue); + } catch (AssertionError e) { + throw new AssertionError("Compared value of " + setting.mKey + " expected " + + value.data + " got " + actualBooleanValue); + } + break; + case TypedValue.TYPE_STRING: + if (!TextUtils.isEmpty(value.string)) { + //This should really be done as a parameterized test + String actualStringValue = getStringForTable(setting, table); + try { + assertEquals(value.string, actualStringValue); + } catch (AssertionError e) { + throw new AssertionError("Compared value of " + setting.mKey + + " expected " + value.string + " got " + actualStringValue); + } + } + break; + case TypedValue.TYPE_NULL: + break; + } + } catch (LineageSettings.LineageSettingNotFoundException e) { + e.printStackTrace(); + throw new AssertionError("Setting " + setting.mKey + " not found!"); + } + } + + private int getIntForTable(Setting setting, String table) + throws LineageSettings.LineageSettingNotFoundException { + switch (table) { + case LineageDatabaseHelper.LineageTableNames.TABLE_SYSTEM: + return LineageSettings.System.getIntForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + case LineageDatabaseHelper.LineageTableNames.TABLE_SECURE: + return LineageSettings.Secure.getIntForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + case LineageDatabaseHelper.LineageTableNames.TABLE_GLOBAL: + return LineageSettings.Global.getIntForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + default: + throw new AssertionError("Invalid or empty table!"); + } + } + + private String getStringForTable(Setting setting, String table) + throws LineageSettings.LineageSettingNotFoundException { + switch (table) { + case LineageDatabaseHelper.LineageTableNames.TABLE_SYSTEM: + return LineageSettings.System.getStringForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + case LineageDatabaseHelper.LineageTableNames.TABLE_SECURE: + return LineageSettings.Secure.getStringForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + case LineageDatabaseHelper.LineageTableNames.TABLE_GLOBAL: + return LineageSettings.Global.getStringForUser(mContentResolver, setting.mKey, + UserHandle.USER_OWNER); + default: + throw new AssertionError("Invalid or empty table!"); + } + } + + private static class Setting { + public String mKey; + public String mDefResName; + public String mType; + + public Setting(String key, String defResId) { + mKey = key; + String[] parts = defResId.split("\\."); + mType = parts[1]; + mDefResName = parts[2]; + } + } + + private Resources getRemoteResources(String packageName) + throws PackageManager.NameNotFoundException { + PackageManager packageManager = mContext.getPackageManager(); + return packageManager.getResourcesForApplication(packageName); + } +} diff --git a/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderTest.java b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderTest.java new file mode 100644 index 00000000..17908ffe --- /dev/null +++ b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsProviderTest.java @@ -0,0 +1,325 @@ + /** + * 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.lineagesettings.tests; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.IContentProvider; +import android.content.pm.UserInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.TextUtils; +import lineageos.providers.LineageSettings; +import org.lineageos.lineagesettings.LineageSettingsProvider; + +import java.util.LinkedHashMap; +import java.util.Map; + + public class LineageSettingsProviderTest extends AndroidTestCase { + private static final String TAG = "LineageSettingsProviderTest"; + + private static final LinkedHashMap<String, String> sMap = new LinkedHashMap<String, String>(); + + static { + sMap.put("testKey1", "value1"); + sMap.put("testKey2", "value2"); + sMap.put("testKey3", "value3"); + } + + private static final String[] PROJECTIONS = new String[] { Settings.NameValueTable.NAME, + Settings.NameValueTable.VALUE }; + + private ContentResolver mContentResolver; + private UserManager mUserManager; + private UserInfo mGuest; + + @Override + public void setUp() { + mContentResolver = mContext.getContentResolver(); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + + @Override + public void tearDown() { + if (mGuest != null) { + mUserManager.removeUser(mGuest.id); + } + } + + @MediumTest + public void testMigrateLineageSettingsForOtherUser() { + // Make sure there's an owner + assertTrue(findUser(mUserManager, UserHandle.USER_OWNER)); + + mGuest = mUserManager.createGuest(mContext, "GuestUser1"); + assertNotNull(mGuest); + + testMigrateSettingsForUser(mGuest.id); + } + + /** + * make sure that queries to SettingsProvider are forwarded to LineageSettingsProvider as needed + * See {@link lineageos.providers.LineageSettings.System#shouldInterceptSystemProvider(String)} + * + * Currently this test only checks that + * {@link lineageos.providers.LineageSettings.System#SYSTEM_PROFILES_ENABLED} is expected to + * be forwarded, and is forwarded. + */ + @SmallTest + public void testSettingsProviderKeyForwarding() { + String forwardedKey = LineageSettings.System.SYSTEM_PROFILES_ENABLED; + + // make sure the key should be forwarded + assertTrue(LineageSettings.System.shouldInterceptSystemProvider(forwardedKey)); + + // put value 1 into Settings provider: + // let's try to disable the profiles via the Settings provider + Settings.System.putStringForUser(mContentResolver, + forwardedKey, "0", UserHandle.USER_CURRENT); + + // assert this is what we just put in there + assertEquals("0", Settings.System.getStringForUser(getContext().getContentResolver(), + forwardedKey, UserHandle.USER_CURRENT)); + + // put value 2 into LineageSettings provider + LineageSettings.System.putStringForUser(mContentResolver, + forwardedKey, "1", UserHandle.USER_CURRENT); + + assertEquals("1", LineageSettings.System.getStringForUser(getContext().getContentResolver(), + forwardedKey, UserHandle.USER_CURRENT)); + + // assert reading from both returns value 2 + final String lineageProviderValue = LineageSettings.System.getStringForUser( + getContext().getContentResolver(), forwardedKey, UserHandle.USER_CURRENT); + final String settingsProviderValue = Settings.System.getStringForUser( + getContext().getContentResolver(), forwardedKey, UserHandle.USER_CURRENT); + assertEquals(lineageProviderValue, settingsProviderValue); + } + + /** + * The new {@link LineageSettings.Secure#LINEAGE_SETUP_WIZARD_COMPLETED} lineage specific provisioned flag + * should be equal to the old {@link Settings.Global#DEVICE_PROVISIONED} flag on boot, or on + * upgrade. These flags will almost always be equal, except during the provisioning process, + * they may change at slightly different times. + * + * Test whether the setting was properly set and is not null. + * + * @deprecated Replaced by {@link Settings.Global#DEVICE_PROVISIONED} + * or {@link Settings.Secure#USER_SETUP_COMPLETE} + */ + @Deprecated + @SmallTest + public void testLineageProvisionedFlagFallbackSet() { + final String newLineageFlag = LineageSettings.Secure.getStringForUser( + getContext().getContentResolver(), LineageSettings.Secure.LINEAGE_SETUP_WIZARD_COMPLETED, + UserHandle.USER_OWNER); + assertNotNull(newLineageFlag); + + final String previousFlag = Settings.Global.getStringForUser( + getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, + UserHandle.USER_OWNER); + assertEquals(previousFlag, newLineageFlag); + } + + private void testMigrateSettingsForUser(int userId) { + // Setup values in Settings + /*final String expectedPullDownValue = "testQuickPullDownValue"; + Settings.System.putStringForUser(mContentResolver, + LineageSettingsProvider.LegacyLineageSettings.STATUS_BAR_QUICK_QS_PULLDOWN, + expectedPullDownValue, userId); + + final int expectedKeyboardBrightness = 4; + Settings.Secure.putIntForUser(mContentResolver, + LineageSettingsProvider.LegacyLineageSettings.KEYBOARD_BRIGHTNESS, + expectedKeyboardBrightness, userId); + + Bundle arg = new Bundle(); + arg.putInt(LineageSettings.CALL_METHOD_USER_KEY, userId); + IContentProvider contentProvider = mContentResolver.acquireProvider( + LineageSettings.AUTHORITY); + + try{ + // Trigger migrate settings for guest + contentProvider.call(mContentResolver.getPackageName(), + LineageSettings.CALL_METHOD_MIGRATE_SETTINGS_FOR_USER, null, arg); + } catch (RemoteException ex) { + fail("Failed to trigger settings migration due to RemoteException"); + } + + // Check values + final String actualPullDownValue = LineageSettings.System.getStringForUser(mContentResolver, + LineageSettings.System.QS_QUICK_PULLDOWN, userId); + assertEquals(expectedPullDownValue, actualPullDownValue); + + final int actualKeyboardBrightness = LineageSettings.Secure.getIntForUser(mContentResolver, + LineageSettings.Secure.KEYBOARD_BRIGHTNESS, -1, userId); + assertEquals(expectedKeyboardBrightness, actualKeyboardBrightness);*/ + } + + private boolean findUser(UserManager userManager, int userHandle) { + for (UserInfo user : userManager.getUsers()) { + if (user.id == userHandle) { + return true; + } + } + return false; + } + + @MediumTest + public void testBulkInsertSuccess() { + ContentValues[] contentValues = new ContentValues[sMap.size()]; + String[] keyValues = new String[sMap.size()]; + int count = 0; + for (Map.Entry<String, String> kVPair : sMap.entrySet()) { + ContentValues contentValue = new ContentValues(); + + final String key = kVPair.getKey(); + contentValue.put(Settings.NameValueTable.NAME, key); + keyValues[count] = key; + + contentValue.put(Settings.NameValueTable.VALUE, kVPair.getValue()); + contentValues[count++] = contentValue; + } + + testBulkInsertForUri(LineageSettings.System.CONTENT_URI, contentValues, keyValues); + testBulkInsertForUri(LineageSettings.Secure.CONTENT_URI, contentValues, keyValues); + testBulkInsertForUri(LineageSettings.Global.CONTENT_URI, contentValues, keyValues); + } + + private void testBulkInsertForUri(Uri uri, ContentValues[] contentValues, String[] keyValues) { + int rowsInserted = mContentResolver.bulkInsert(uri, contentValues); + assertEquals(sMap.size(), rowsInserted); + + final String placeholderSymbol = "?"; + String[] placeholders = new String[contentValues.length]; + for (int i = 0; i < placeholders.length; i++) { + placeholders[i] = placeholderSymbol; + } + + final String placeholdersString = TextUtils.join(",", placeholders); + + Cursor queryCursor = mContentResolver.query(uri, PROJECTIONS, + Settings.NameValueTable.NAME + " IN (" + placeholdersString + ")", keyValues, + null); + assertEquals(contentValues.length, queryCursor.getCount()); + try { + while (queryCursor.moveToNext()) { + assertEquals(PROJECTIONS.length, queryCursor.getColumnCount()); + + String actualKey = queryCursor.getString(0); + assertTrue(sMap.containsKey(actualKey)); + + assertEquals(sMap.get(actualKey), queryCursor.getString(1)); + } + } + finally { + queryCursor.close(); + } + + // TODO: Find a better way to cleanup database/use ProviderTestCase2 without process crash + for (String key : sMap.keySet()) { + mContentResolver.delete(uri, Settings.NameValueTable.NAME + " = ?", + new String[]{ key }); + } + } + + @MediumTest + public void testInsertUpdateDeleteSuccess() { + //testInsertUpdateDeleteForUri(LineageSettings.System.CONTENT_URI); + testInsertUpdateDeleteForUri(LineageSettings.Secure.CONTENT_URI); + testInsertUpdateDeleteForUri(LineageSettings.Global.CONTENT_URI); + } + + private void testInsertUpdateDeleteForUri(Uri uri) { + String key = "key"; + String value1 = "value1"; + String value2 = "value2"; + + // test insert + ContentValues contentValue = new ContentValues(); + contentValue.put(Settings.NameValueTable.NAME, key); + contentValue.put(Settings.NameValueTable.VALUE, value1); + + Uri expectedUri = uri.withAppendedPath(uri, key); + Uri returnUri = mContentResolver.insert(uri, contentValue); + assertEquals(expectedUri, returnUri); + + Cursor queryCursor = null; + try { + // check insert + queryCursor = mContentResolver.query(uri, PROJECTIONS, Settings.NameValueTable.NAME + + " = ?", new String[]{ key }, null); + assertEquals(1, queryCursor.getCount()); + + assertExpectedKeyValuePair(queryCursor, key, value1); + + // check insert with returned uri + queryCursor = mContentResolver.query(returnUri, PROJECTIONS, null, null, null); + assertEquals(1, queryCursor.getCount()); + + assertExpectedKeyValuePair(queryCursor, key, value1); + + // test update + contentValue.clear(); + contentValue.put(Settings.NameValueTable.VALUE, value2); + + int rowsAffected = mContentResolver.update(uri, contentValue, + Settings.NameValueTable.NAME + " = ?", new String[]{ key }); + assertEquals(1, rowsAffected); + + // check update + queryCursor = mContentResolver.query(uri, PROJECTIONS, Settings.NameValueTable.NAME + + " = ?", new String[]{ key }, null); + assertEquals(1, queryCursor.getCount()); + + assertExpectedKeyValuePair(queryCursor, key, value2); + + // test delete + rowsAffected = mContentResolver.delete(uri, Settings.NameValueTable.NAME + " = ?", + new String[]{ key }); + assertEquals(1, rowsAffected); + + // check delete + queryCursor = mContentResolver.query(uri, PROJECTIONS, Settings.NameValueTable.NAME + + " = ?", new String[]{ key }, null); + assertEquals(0, queryCursor.getCount()); + } finally { + if (queryCursor != null) { + queryCursor.close(); + } + } + } + + private void assertExpectedKeyValuePair(Cursor cursor, String expectedKey, + String expectedValue) { + cursor.moveToNext(); + assertEquals(PROJECTIONS.length, cursor.getColumnCount()); + + String actualKey = cursor.getString(0); + assertEquals(expectedKey, actualKey); + assertEquals(expectedValue, cursor.getString(1)); + } + } diff --git a/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSecureTests.java b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSecureTests.java new file mode 100644 index 00000000..b27accad --- /dev/null +++ b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSecureTests.java @@ -0,0 +1,126 @@ +/** + * 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.lineagesettings.tests; + +import android.content.ContentResolver; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.LineageSettings; + +public class LineageSettingsSecureTests extends AndroidTestCase { + private ContentResolver mContentResolver; + + private static final String UNREALISTIC_SETTING = "_______UNREAL_______"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContentResolver = mContext.getContentResolver(); + } + + @SmallTest + public void testFloat() { + final float expectedFloatValue = 1.0f; + LineageSettings.Secure.putFloat(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER, expectedFloatValue); + + try { + float actualValue = LineageSettings.Secure.getFloat(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedFloatValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testFloatWithDefault() { + final float expectedDefaultFloatValue = 1.5f; + float actualValue = LineageSettings.Secure.getFloat(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultFloatValue); + assertEquals(expectedDefaultFloatValue, actualValue); + } + + @SmallTest + public void testInt() { + final int expectedIntValue = 2; + LineageSettings.Secure.putInt(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER, expectedIntValue); + + try { + int actualValue = LineageSettings.Secure.getInt(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedIntValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testIntWithDefault() { + final int expectedDefaultIntValue = 11; + int actualValue = LineageSettings.Secure.getInt(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultIntValue); + assertEquals(expectedDefaultIntValue, actualValue); + } + + @SmallTest + public void testLong() { + final long expectedLongValue = 3l; + LineageSettings.Secure.putLong(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER, expectedLongValue); + + try { + long actualValue = LineageSettings.Secure.getLong(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedLongValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testLongWithDefault() { + final long expectedDefaultLongValue = 17l; + long actualValue = LineageSettings.Secure.getLong(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultLongValue); + assertEquals(expectedDefaultLongValue, actualValue); + } + + @SmallTest + public void testString() { + final String expectedStringValue = "4"; + LineageSettings.Secure.putString(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER, expectedStringValue); + + String actualValue = LineageSettings.Secure.getString(mContentResolver, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedStringValue, actualValue); + } + + @SmallTest + public void testGetUri() { + final Uri expectedUri = Uri.withAppendedPath(LineageSettings.Secure.CONTENT_URI, + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + + final Uri actualUri = LineageSettings.Secure.getUriFor( + LineageSettings.Secure.__MAGICAL_TEST_PASSING_ENABLER); + + assertEquals(expectedUri, actualUri); + } +} diff --git a/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSystemTests.java b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSystemTests.java new file mode 100644 index 00000000..101a60f4 --- /dev/null +++ b/packages/LineageSettingsProvider/tests/src/org/lineageos/lineagesettings/tests/LineageSettingsSystemTests.java @@ -0,0 +1,126 @@ +/** + * 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.lineagesettings.tests; + +import android.content.ContentResolver; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import lineageos.providers.LineageSettings; + +public class LineageSettingsSystemTests extends AndroidTestCase { + private ContentResolver mContentResolver; + + private static final String UNREALISTIC_SETTING = "_______UNREAL_______"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContentResolver = mContext.getContentResolver(); + } + + @SmallTest + public void testFloat() { + final float expectedFloatValue = 1.0f; + LineageSettings.System.putFloat(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER, expectedFloatValue); + + try { + float actualValue = LineageSettings.System.getFloat(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedFloatValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testFloatWithDefault() { + final float expectedDefaultFloatValue = 1.5f; + float actualValue = LineageSettings.System.getFloat(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultFloatValue); + assertEquals(expectedDefaultFloatValue, actualValue); + } + + @SmallTest + public void testInt() { + final int expectedIntValue = 2; + LineageSettings.System.putInt(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER, expectedIntValue); + + try { + int actualValue = LineageSettings.System.getInt(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedIntValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testIntWithDefault() { + final int expectedDefaultIntValue = 11; + int actualValue = LineageSettings.System.getInt(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultIntValue); + assertEquals(expectedDefaultIntValue, actualValue); + } + + @SmallTest + public void testLong() { + final long expectedLongValue = 3l; + LineageSettings.System.putLong(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER, expectedLongValue); + + try { + long actualValue = LineageSettings.System.getLong(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedLongValue, actualValue); + } catch (LineageSettings.LineageSettingNotFoundException e) { + throw new AssertionError(e); + } + } + + @SmallTest + public void testLongWithDefault() { + final long expectedDefaultLongValue = 17l; + long actualValue = LineageSettings.System.getLong(mContentResolver, + UNREALISTIC_SETTING, expectedDefaultLongValue); + assertEquals(expectedDefaultLongValue, actualValue); + } + + @SmallTest + public void testString() { + final String expectedStringValue = "4"; + LineageSettings.System.putString(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER, expectedStringValue); + + String actualValue = LineageSettings.System.getString(mContentResolver, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + assertEquals(expectedStringValue, actualValue); + } + + @SmallTest + public void testGetUri() { + final Uri expectedUri = Uri.withAppendedPath(LineageSettings.System.CONTENT_URI, + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + + final Uri actualUri = LineageSettings.System.getUriFor( + LineageSettings.System.__MAGICAL_TEST_PASSING_ENABLER); + + assertEquals(expectedUri, actualUri); + } +} diff --git a/sdk/src/java/org/lineageos/internal/util/TelephonyExtUtils.java b/sdk/src/java/org/lineageos/internal/util/TelephonyExtUtils.java index 831f7578..59f6d10f 100644 --- a/sdk/src/java/org/lineageos/internal/util/TelephonyExtUtils.java +++ b/sdk/src/java/org/lineageos/internal/util/TelephonyExtUtils.java @@ -20,10 +20,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.AsyncTask; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; import android.telephony.SubscriptionManager; import android.util.Log; @@ -33,8 +31,6 @@ import org.codeaurora.internal.IExtTelephony; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.TimeUnit; public final class TelephonyExtUtils { private static final boolean DEBUG = false; @@ -45,9 +41,6 @@ public final class TelephonyExtUtils { public static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState"; - private static final int ACTIVATE_TIME_OUT = 30000; - private static final String PROP_TIME_OUT = "sys.uicc.activate.timeout"; - // This is the list of possible values that // IExtTelephony.getCurrentUiccCardProvisioningStatus() can return public static final int CARD_NOT_PRESENT = -2; @@ -154,7 +147,15 @@ public final class TelephonyExtUtils { * @return The result of the activation or -1 */ public int activateUiccCard(int slotId) { - return activateDeactivateUiccCard(true, slotId); + IExtTelephony service = getService(); + if (service != null) { + try { + return mExtTelephony.activateUiccCard(slotId); + } catch (RemoteException ex) { + Log.e(TAG, "Activating sub failed for slotId: " + slotId); + } + } + return -1; } /** @@ -163,38 +164,14 @@ public final class TelephonyExtUtils { * @return The result of the deactivation or -1 */ public int deactivateUiccCard(int slotId) { - return activateDeactivateUiccCard(false, slotId); - } - - private int activateDeactivateUiccCard(boolean activate, int slotId) { IExtTelephony service = getService(); - if (service == null) { - return -1; - } - - try { - AsyncTask<Integer, Void, Integer> task = new AsyncTask<Integer, Void, Integer>() { - @Override - protected Integer doInBackground(Integer... params) { - try { - return params[0] == 1 - ? mExtTelephony.activateUiccCard(params[1]) - : mExtTelephony.deactivateUiccCard(params[1]); - } catch (RemoteException ex) { - Log.e(TAG, "Changing activation for sub failed for slotId: " + params[1]); - } - return -1; - } - }; - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, activate ? 1 : 0, slotId) - .get(ACTIVATE_TIME_OUT, TimeUnit.MILLISECONDS); - } catch (TimeoutException ex) { - Log.e(TAG, "Changing activation for sub timed out for slotId: " + slotId); - SystemProperties.set(PROP_TIME_OUT , Integer.toString(slotId + 1)); - } catch (Exception ex) { - Log.e(TAG, "Changing activation for sub task failed for slotId: " + slotId); + if (service != null) { + try { + return mExtTelephony.deactivateUiccCard(slotId); + } catch (RemoteException ex) { + Log.e(TAG, "Deactivating sub failed for slotId: " + slotId); + } } - return -1; } diff --git a/tests/Android.mk b/tests/Android.mk new file mode 100644 index 00000000..2cbb309f --- /dev/null +++ b/tests/Android.mk @@ -0,0 +1,56 @@ +# +# 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. +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_STATIC_JAVA_LIBRARIES := \ + org.lineageos.platform.sdk \ + android-support-test \ + mockito-target + +LOCAL_DEX_PREOPT := false + +LOCAL_SRC_FILES := $(call all-subdir-java-files, src/) + +LOCAL_PACKAGE_NAME := LineagePlatformTests +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_PROGUARD_ENABLED := optimization shrinktests +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +include $(BUILD_PACKAGE) + +# Register as LineageTS +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests + +LOCAL_STATIC_JAVA_LIBRARIES := \ + org.lineageos.platform.sdk \ + android-support-test \ + mockito-target + +LOCAL_DEX_PREOPT := false + +LOCAL_SRC_FILES := $(call all-subdir-java-files, src/) + +LOCAL_PACKAGE_NAME := CmtsPlatformSDKTests +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_PROGUARD_ENABLED := optimization shrinktests +LOCAL_PROGUARD_FLAG_FILES := proguard.flags +include $(BUILD_LineageTS_PACKAGE) diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml new file mode 100644 index 00000000..174a1600 --- /dev/null +++ b/tests/AndroidManifest.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.lineageos.tests" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.REBOOT" /> + <uses-permission android:name="com.android.alarm.permission.SET_ALARM" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" /> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> + + <uses-permission android:name="lineageos.permission.BIND_CUSTOM_TILE_LISTENER_SERVICE"/> + <uses-permission android:name="lineageos.permission.PUBLISH_CUSTOM_TILE"/> + <uses-permission android:name="lineageos.permission.WRITE_SETTINGS"/> + <uses-permission android:name="lineageos.permission.WRITE_SECURE_SETTINGS"/> + <uses-permission android:name="lineageos.permission.MODIFY_NETWORK_SETTINGS" /> + <uses-permission android:name="lineageos.permission.MODIFY_SOUND_SETTINGS" /> + <uses-permission android:name="lineageos.permission.MANAGE_ALARMS" /> + <uses-permission android:name="lineageos.permission.READ_ALARMS" /> + <uses-permission android:name="lineageos.permission.MODIFY_MSIM_PHONE_STATE" /> + <uses-permission android:name="lineageos.permission.READ_MSIM_PHONE_STATE" /> + <uses-permission android:name="lineageos.permission.HARDWARE_ABSTRACTION_ACCESS" /> + <uses-permission android:name="lineageos.permission.MODIFY_PROFILES" /> + <uses-permission android:name="lineageos.permission.MANAGE_PERSISTENT_STORAGE" /> + <uses-permission android:name="lineageos.permission.PERFORMANCE_ACCESS" /> + <uses-permission android:name="lineageos.permission.MANAGE_LIVEDISPLAY" /> + <uses-permission android:name="lineageos.permission.OBSERVE_AUDIO_SESSIONS" /> + <uses-permission android:name="lineageos.permission.ACCESS_WEATHER_MANAGER" /> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + + <application android:name=".LineageOSTestApplication" + android:label="@string/app_name" android:icon="@drawable/ic_launcher"> + <uses-library android:name="android.test.runner" /> + <activity android:name=".customtiles.LineageStatusBarTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".alarmclock.LineageAlarmClockTest" + android:label="@string/alarm_tests_activity_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".telephony.LineageTelephonyTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".profiles.ProfileTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".versioning.VersioningTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".hardware.LineageHardwareTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + + <activity android:name=".customtiles.DummySettings" + android:label="@string/app_name" /> + </application> + + <instrumentation + android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="org.lineageos.tests" /> +</manifest> diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..9aebffc8 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,7 @@ +## Lineage Platform SDK Tests +The tests package contains both functional manual tests as well as unit +tests which can be ran utilizing the InstrumentationTestRunner from android. + +To run the tests (on a live device): + + ```adb shell am instrument -w org.lineageos.tests/android.support.test.runner.AndroidJUnitRunner``` diff --git a/tests/proguard.flags b/tests/proguard.flags new file mode 100644 index 00000000..fd080271 --- /dev/null +++ b/tests/proguard.flags @@ -0,0 +1,56 @@ +# 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. + +# Don't skip non public library classes, make sure we're not keeping anything which will get mapped against api verification. +-dontskipnonpubliclibraryclasses + +# Do the same with class members +-dontskipnonpubliclibraryclassmembers + +# Keep test packages +-keep class android.support.** { *; } +-keep class android.test.** { *; } +-keep public class * extends android.support.** { *; } +-keep public class * extends android.test.** { *; } +-keep interface android.support.** { *; } +-keep interface android.test.** { *; } + +# Keep all junit classes +-keep class junit.** { *; } +-keep class org.junit.** { *; } +-keep interface junit.** { *; } +-keep interface org.junit.** { *; } + +# Keep compiled java classes from declared aidl's within the test package +-keep public class * extends android.os.IInterface { *; } + +# Don't warn about the Android Support Test JUnit Runner +-dontwarn android.support.** +-dontwarn android.test.** + +# Don't warn about junit +-dontwarn junit.** +-dontwarn org.junit.** + +# keep mockito methods +-keep class org.mockito.** { *; } +-keep interface org.mockito.** { *; } +-keep class com.google.dexmaker.** { *; } +-keep interface com.google.dexmaker.** { *; } + +# Always process +-forceprocessing + +# Make sure not to obfuscate the output +-dontobfuscate diff --git a/tests/res/drawable-hdpi/ic_launcher.png b/tests/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..cde69bcc --- /dev/null +++ b/tests/res/drawable-hdpi/ic_launcher.png diff --git a/tests/res/drawable-hdpi/ic_whatshot_white_24dp.png b/tests/res/drawable-hdpi/ic_whatshot_white_24dp.png Binary files differnew file mode 100644 index 00000000..46ed1f8b --- /dev/null +++ b/tests/res/drawable-hdpi/ic_whatshot_white_24dp.png diff --git a/tests/res/drawable-mdpi/ic_launcher.png b/tests/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..c133a0cb --- /dev/null +++ b/tests/res/drawable-mdpi/ic_launcher.png diff --git a/tests/res/drawable-mdpi/ic_whatshot_white_24dp.png b/tests/res/drawable-mdpi/ic_whatshot_white_24dp.png Binary files differnew file mode 100644 index 00000000..4cf6f85f --- /dev/null +++ b/tests/res/drawable-mdpi/ic_whatshot_white_24dp.png diff --git a/tests/res/drawable-xhdpi/ic_launcher.png b/tests/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..bfa42f0e --- /dev/null +++ b/tests/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/res/drawable-xhdpi/ic_whatshot_white_24dp.png b/tests/res/drawable-xhdpi/ic_whatshot_white_24dp.png Binary files differnew file mode 100644 index 00000000..3651d061 --- /dev/null +++ b/tests/res/drawable-xhdpi/ic_whatshot_white_24dp.png diff --git a/tests/res/drawable-xxhdpi/ic_launcher.png b/tests/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..324e72cd --- /dev/null +++ b/tests/res/drawable-xxhdpi/ic_launcher.png diff --git a/tests/res/drawable-xxhdpi/ic_whatshot_white_24dp.png b/tests/res/drawable-xxhdpi/ic_whatshot_white_24dp.png Binary files differnew file mode 100644 index 00000000..8eaf3755 --- /dev/null +++ b/tests/res/drawable-xxhdpi/ic_whatshot_white_24dp.png diff --git a/tests/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png b/tests/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png Binary files differnew file mode 100644 index 00000000..5c5d8687 --- /dev/null +++ b/tests/res/drawable-xxxhdpi/ic_whatshot_white_24dp.png diff --git a/tests/res/layout/main.xml b/tests/res/layout/main.xml new file mode 100644 index 00000000..15b422cd --- /dev/null +++ b/tests/res/layout/main.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_horizontal" + > + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST PUBLISH TILE" + android:onClick="testPublishTile"/> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST PUBLISH SETTINGS TILE" + android:onClick="testPublishTileWithSettings"/> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST UPDATE TILE" + android:onClick="testUpdateTile"/> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST REMOVE TILE" + android:onClick="testRemoveTile"/> + + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST PUBLISH MULTIPLE" + android:onClick="testMultipleTilePublish"/> + <Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="TEST REMOVE MULTIPLE" + android:onClick="testMultipleTileRemove"/> +</LinearLayout> + diff --git a/tests/res/layout/remote_view.xml b/tests/res/layout/remote_view.xml new file mode 100644 index 00000000..6988cf95 --- /dev/null +++ b/tests/res/layout/remote_view.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal"> + + <ImageView + android:src="@drawable/ic_whatshot_white_24dp" + android:layout_width="48dp" + android:layout_height="48dp" /> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:text="THIS IS A REMOTEVIEW" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <Button + android:id="@+id/whats_hot_click" + android:text="CLICK ME" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml new file mode 100644 index 00000000..5cbd37c5 --- /dev/null +++ b/tests/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">Lineage Platform Tests</string> + <string name="settings_tests_activity_name">Lineage Platform Settings Tests</string> + <string name="alarm_tests_activity_name">Lineage Platform Alarm Clock Tests</string> +</resources> 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); + } + } +} |