OSDN Git Service

72a03b2d7066635d926246fbe5e22bc174d0f175
[android-x86/packages-apps-Taskbar.git] / app / src / test / java / com / farmerbb / taskbar / util / UTest.java
1 package com.farmerbb.taskbar.util;
2
3 import android.Manifest;
4 import android.accessibilityservice.AccessibilityService;
5 import android.app.ActivityOptions;
6 import android.app.AlertDialog;
7 import android.app.Application;
8 import android.content.BroadcastReceiver;
9 import android.content.ComponentName;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.IntentFilter;
13 import android.content.SharedPreferences;
14 import android.content.pm.PackageManager;
15 import android.content.res.Resources;
16 import android.graphics.Color;
17 import android.provider.Settings;
18 import android.view.WindowManager;
19 import android.widget.Button;
20 import android.widget.Toast;
21
22 import androidx.appcompat.view.ContextThemeWrapper;
23 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
24 import androidx.test.core.app.ApplicationProvider;
25
26 import com.farmerbb.taskbar.R;
27 import com.farmerbb.taskbar.helper.FreeformHackHelper;
28 import com.farmerbb.taskbar.mockito.BooleanAnswer;
29 import com.farmerbb.taskbar.mockito.IntAnswer;
30 import com.farmerbb.taskbar.service.PowerMenuService;
31
32 import org.junit.Before;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.powermock.api.mockito.PowerMockito;
37 import org.powermock.core.classloader.annotations.PowerMockIgnore;
38 import org.powermock.core.classloader.annotations.PrepareForTest;
39 import org.powermock.modules.junit4.rule.PowerMockRule;
40 import org.robolectric.RobolectricTestRunner;
41 import org.robolectric.Shadows;
42 import org.robolectric.annotation.Config;
43 import org.robolectric.annotation.LooperMode;
44 import org.robolectric.shadows.ShadowAlertDialog;
45 import org.robolectric.shadows.ShadowApplication;
46 import org.robolectric.shadows.ShadowBuild;
47 import org.robolectric.shadows.ShadowLooper;
48 import org.robolectric.shadows.ShadowPackageManager;
49 import org.robolectric.shadows.ShadowSettings;
50 import org.robolectric.shadows.ShadowToast;
51 import org.robolectric.util.ReflectionHelpers;
52
53 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
54 import static org.junit.Assert.assertEquals;
55 import static org.junit.Assert.assertFalse;
56 import static org.junit.Assert.assertNotNull;
57 import static org.junit.Assert.assertTrue;
58 import static org.mockito.Matchers.any;
59 import static org.powermock.api.mockito.PowerMockito.when;
60 import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
61
62 import static com.farmerbb.taskbar.util.Constants.*;
63
64 @RunWith(RobolectricTestRunner.class)
65 @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "androidx.*"})
66 @PrepareForTest(U.class)
67 @LooperMode(LooperMode.Mode.LEGACY)
68 public class UTest {
69     @Rule
70     public PowerMockRule rule = new PowerMockRule();
71
72     private Context context;
73
74     @Before
75     public void setUp() {
76         context = ApplicationProvider.getApplicationContext();
77         assertNotNull(context);
78     }
79
80     @Test
81     public void testShowPermissionDialogWithAndroidTVSettings() throws Exception {
82         testShowPermissionDialog(
83                 true,
84                 context.getResources().getString(R.string.tb_permission_dialog_message)
85                         + context.getResources().getString(R.string.tb_permission_dialog_instructions_tv),
86                 R.string.tb_action_open_settings
87         );
88     }
89
90     @Test
91     public void testShowPermissionDialogNormal() throws Exception {
92         testShowPermissionDialog(
93                 false,
94                 context.getResources().getString(R.string.tb_permission_dialog_message)
95                         + context.getResources().getString(R.string.tb_permission_dialog_instructions_phone),
96                 R.string.tb_action_grant_permission
97         );
98     }
99
100     private void testShowPermissionDialog(boolean hasAndroidTVSettings,
101                                           String message,
102                                           int buttonTextResId) throws Exception {
103         RunnableHooker onError = new RunnableHooker();
104         RunnableHooker onFinish = new RunnableHooker();
105         PowerMockito.spy(U.class);
106         when(U.class, "hasAndroidTVSettings", context).thenReturn(hasAndroidTVSettings);
107         AlertDialog dialog = U.showPermissionDialog(context, new Callbacks(onError, onFinish));
108         ShadowAlertDialog shadowDialog = Shadows.shadowOf(dialog);
109         Resources resources = context.getResources();
110         assertEquals(
111                 resources.getString(R.string.tb_permission_dialog_title),
112                 shadowDialog.getTitle()
113         );
114         assertEquals(message, shadowDialog.getMessage());
115         Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
116         assertEquals(resources.getString(buttonTextResId), positiveButton.getText());
117         assertFalse(shadowDialog.isCancelable());
118         positiveButton.performClick();
119         assertTrue(onFinish.hasRun());
120         assertFalse(onError.hasRun());
121     }
122
123     @Test
124     public void testShowErrorDialog() {
125         RunnableHooker onFinish = new RunnableHooker();
126         String appOpCommand = "app-op-command";
127         AlertDialog dialog =
128                 ReflectionHelpers.callStaticMethod(
129                         U.class,
130                         "showErrorDialog",
131                         from(Context.class, context),
132                         from(String.class, appOpCommand),
133                         from(Callbacks.class, new Callbacks(null, onFinish))
134                 );
135         ShadowAlertDialog shadowDialog = Shadows.shadowOf(dialog);
136         Resources resources = context.getResources();
137         assertEquals(
138                 resources.getString(R.string.tb_error_dialog_title),
139                 shadowDialog.getTitle()
140         );
141         assertEquals(
142                 resources.getString(
143                         R.string.tb_error_dialog_message,
144                         context.getPackageName(),
145                         appOpCommand
146                 ),
147                 shadowDialog.getMessage()
148         );
149         Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
150         assertEquals(resources.getString(R.string.tb_action_ok), button.getText());
151         assertFalse(shadowDialog.isCancelable());
152         button.performClick();
153         assertTrue(onFinish.hasRun());
154     }
155
156     @Test
157     public void testSendAccessibilityActionWithServiceNotEnabledAndGrantedPermission() {
158         testSendAccessibilityAction(false, true, true);
159     }
160
161     @Test
162     public void testSendAccessibilityActionWithServiceEnabled() {
163         testSendAccessibilityAction(true, false, true);
164     }
165
166     @Test
167     public void testSendAccessibilityActionWithServiceNotEnabledAndWithoutPermission() {
168         testSendAccessibilityAction(false, false, false);
169     }
170
171     private void testSendAccessibilityAction(boolean serviceEnabled,
172                                              boolean hasPermission,
173                                              boolean hasRun) {
174         PowerMockito.spy(U.class);
175         when(U.isAccessibilityServiceEnabled(context)).thenReturn(serviceEnabled);
176         when(U.hasWriteSecureSettingsPermission(context)).thenReturn(hasPermission);
177         RunnableHooker onComplete = new RunnableHooker();
178         U.sendAccessibilityAction(
179                 context, AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN, onComplete
180         );
181         // Run all delayed message.
182         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
183         assertEquals(hasRun, onComplete.hasRun());
184     }
185
186     @Test
187     public void testIsAccessibilityServiceEnabled() {
188         String enabledServices =
189                 Settings.Secure.getString(
190                         context.getContentResolver(),
191                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
192                 );
193         ComponentName componentName = new ComponentName(context, PowerMenuService.class);
194         String flattenString = componentName.flattenToString();
195         String flattenShortString = componentName.flattenToShortString();
196         String newEnabledService =
197                 enabledServices == null ?
198                         "" :
199                         enabledServices
200                                 .replaceAll(":" + flattenString, "")
201                                 .replaceAll(":" + flattenShortString, "")
202                                 .replaceAll(flattenString, "")
203                                 .replaceAll(flattenShortString, "");
204         Settings.Secure.putString(
205                 context.getContentResolver(),
206                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
207                 newEnabledService
208         );
209         assertFalse(U.isAccessibilityServiceEnabled(context));
210         Settings.Secure.putString(
211                 context.getContentResolver(),
212                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
213                 newEnabledService + ":" + flattenString
214         );
215         assertTrue(U.isAccessibilityServiceEnabled(context));
216         Settings.Secure.putString(
217                 context.getContentResolver(),
218                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
219                 newEnabledService + ":" + flattenShortString
220         );
221         assertTrue(U.isAccessibilityServiceEnabled(context));
222         Settings.Secure.putString(
223                 context.getContentResolver(),
224                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
225                 enabledServices
226         );
227     }
228
229     @Test
230     public void testHasWriteSecureSettingsPermissionForMarshmallowAndAboveVersion() {
231         assertFalse(U.hasWriteSecureSettingsPermission(context));
232         Application application = ApplicationProvider.getApplicationContext();
233         ShadowApplication shadowApplication = Shadows.shadowOf(application);
234         shadowApplication.grantPermissions(Manifest.permission.WRITE_SECURE_SETTINGS);
235         assertTrue(U.hasWriteSecureSettingsPermission(context));
236     }
237
238     @Test
239     @Config(sdk = 21)
240     public void testHasWriteSecureSettingsPermissionVersionBelowMarshmallow() {
241         Application application = ApplicationProvider.getApplicationContext();
242         ShadowApplication shadowApplication = Shadows.shadowOf(application);
243         shadowApplication.grantPermissions(Manifest.permission.WRITE_SECURE_SETTINGS);
244         assertFalse(U.hasWriteSecureSettingsPermission(context));
245     }
246
247     @Test
248     public void testShowToast() {
249         U.showToast(context, R.string.tb_pin_shortcut_not_supported);
250         Toast toast = ShadowToast.getLatestToast();
251         assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
252         assertEquals(
253                 context.getResources().getString(R.string.tb_pin_shortcut_not_supported),
254                 ShadowToast.getTextOfLatestToast()
255         );
256     }
257
258     @Test
259     public void testShowLongToast() {
260         U.showToastLong(context, R.string.tb_pin_shortcut_not_supported);
261         Toast toast = ShadowToast.getLatestToast();
262         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
263         assertEquals(
264                 context.getResources().getString(R.string.tb_pin_shortcut_not_supported),
265                 ShadowToast.getTextOfLatestToast()
266         );
267     }
268
269     @Test
270     public void testCancelToast() {
271         U.showToastLong(context, R.string.tb_pin_shortcut_not_supported);
272         ShadowToast shadowToast = Shadows.shadowOf(ShadowToast.getLatestToast());
273         assertFalse(shadowToast.isCancelled());
274         U.cancelToast();
275         assertTrue(shadowToast.isCancelled());
276     }
277
278     @Test
279     public void testCanEnableFreeformWithNougatAndAboveVersion() {
280         assertTrue(U.canEnableFreeform());
281     }
282
283     @Test
284     @Config(sdk = 23)
285     public void testCanEnableFreeformWithMarshmallowAndBelowVersion() {
286         assertFalse(U.canEnableFreeform());
287     }
288
289     @Test
290     public void testHasFreeformSupportWithoutFreeformEnabled() {
291         PowerMockito.spy(U.class);
292         when(U.canEnableFreeform()).thenReturn(false);
293         assertFalse(U.canEnableFreeform());
294     }
295
296     @Test
297     public void testHasFreeformSupportWithFreeformEnabledAndNMR1AboveVersion() {
298         PowerMockito.spy(U.class);
299         when(U.canEnableFreeform()).thenReturn(true);
300         assertFalse(U.hasFreeformSupport(context));
301         // Case 1, system has feature freeform.
302         PackageManager packageManager = context.getPackageManager();
303         ShadowPackageManager shadowPackageManager = Shadows.shadowOf(packageManager);
304         shadowPackageManager
305                 .setSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, true);
306         assertTrue(U.hasFreeformSupport(context));
307         shadowPackageManager
308                 .setSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, false);
309         // Case 2, enable_freeform_support in Settings.Global is not 0
310         Settings.Global.putInt(context.getContentResolver(), "enable_freeform_support", 1);
311         assertTrue(U.hasFreeformSupport(context));
312         Settings.Global.putInt(context.getContentResolver(), "enable_freeform_support", 0);
313     }
314
315     @Test
316     @Config(sdk = 25)
317     public void testHasFreeformSupportWithFreeformEnabledAndNMR1AndBelowVersion() {
318         PowerMockito.spy(U.class);
319         when(U.canEnableFreeform()).thenReturn(true);
320         assertFalse(U.hasFreeformSupport(context));
321         // Case 3, version is less than or equal to N_MRI, and force_resizable_activities
322         // in Settings.Global is not 0
323         Settings.Global.putInt(context.getContentResolver(), "force_resizable_activities", 1);
324         assertTrue(U.hasFreeformSupport(context));
325         Settings.Global.putInt(context.getContentResolver(), "force_resizable_activities", 0);
326     }
327
328     @Test
329     public void testCanBootToFreeform() {
330         PowerMockito.spy(U.class);
331         BooleanAnswer hasFreeformSupportAnswer = new BooleanAnswer();
332         BooleanAnswer isOverridingFreeformHackAnswer = new BooleanAnswer();
333         when(U.hasFreeformSupport(context)).thenAnswer(hasFreeformSupportAnswer);
334         when(U.isOverridingFreeformHack(context, true)).thenAnswer(isOverridingFreeformHackAnswer);
335         // Case 1, all return true
336         hasFreeformSupportAnswer.answer = true;
337         isOverridingFreeformHackAnswer.answer = true;
338         assertFalse(U.canBootToFreeform(context));
339         // Case 2, true, false
340         hasFreeformSupportAnswer.answer = true;
341         isOverridingFreeformHackAnswer.answer = false;
342         assertTrue(U.canBootToFreeform(context));
343         // Case 3, false, true
344         hasFreeformSupportAnswer.answer = false;
345         isOverridingFreeformHackAnswer.answer = true;
346         assertFalse(U.canBootToFreeform(context));
347         // Case 4, false, false
348         hasFreeformSupportAnswer.answer = false;
349         isOverridingFreeformHackAnswer.answer = false;
350         assertFalse(U.canBootToFreeform(context));
351     }
352
353     @Test
354     public void testIsSamsungDevice() {
355         ShadowBuild.setManufacturer("Samsung");
356         assertTrue(U.isSamsungDevice());
357         ShadowBuild.setManufacturer("samsung");
358         assertTrue(U.isSamsungDevice());
359         ShadowBuild.setManufacturer("UnSamsung");
360         assertFalse(U.isSamsungDevice());
361     }
362
363     @Test
364     public void testGetBackgroundTint() {
365         SharedPreferences prefs = U.getSharedPreferences(context);
366         prefs.edit()
367                 .putInt(PREF_BACKGROUND_TINT, Color.GREEN)
368                 .putBoolean(PREF_SHOW_BACKGROUND, false)
369                 .apply();
370         // If the SHOW_BACKGROUND is false, it use transparent to replace origin tint.
371         assertEquals(Color.TRANSPARENT, U.getBackgroundTint(context));
372         prefs.edit()
373                 .putInt(PREF_BACKGROUND_TINT, Color.GREEN)
374                 .apply();
375         assertEquals(Color.GREEN, U.getBackgroundTint(context));
376         prefs.edit().remove(PREF_BACKGROUND_TINT).apply();
377         assertEquals(
378                 context.getResources().getInteger(R.integer.tb_translucent_gray),
379                 U.getBackgroundTint(context)
380         );
381     }
382
383     @Test
384     public void testAccentColor() {
385         SharedPreferences prefs = U.getSharedPreferences(context);
386         prefs.edit().remove(PREF_ACCENT_COLOR).apply();
387         assertEquals(
388                 context.getResources().getInteger(R.integer.tb_translucent_white),
389                 U.getAccentColor(context)
390         );
391         prefs.edit().putInt(PREF_ACCENT_COLOR, Color.GREEN).apply();
392         assertEquals(Color.GREEN, U.getAccentColor(context));
393     }
394
395     @Test
396     public void testCanDrawOverlaysWithMarshmallowAndAboveVersion() {
397         ShadowSettings.setCanDrawOverlays(true);
398         assertTrue(U.canDrawOverlays(context));
399         ShadowSettings.setCanDrawOverlays(false);
400         assertFalse(U.canDrawOverlays(context));
401     }
402
403     @Test
404     @Config(sdk = 22)
405     public void testCanDrawOverlaysWithMarshmallowBelowVersion() {
406         assertTrue(U.canDrawOverlays(context));
407     }
408
409     @Test
410     public void testIsGame() {
411         // We only test for un-support launching games fullscreen, because of
412         // we don't have a good method to test code with ApplicationInfo.
413         SharedPreferences prefs = U.getSharedPreferences(context);
414         prefs.edit().putBoolean(PREF_LAUNCH_GAMES_FULLSCREEN, false).apply();
415         assertFalse(U.isGame(context, context.getPackageName()));
416         prefs.edit().putBoolean(PREF_LAUNCH_GAMES_FULLSCREEN, true).apply();
417         assertFalse(U.isGame(context, context.getPackageName()));
418         assertFalse(U.isGame(context, context.getPackageName() + "un-exist-package"));
419     }
420
421     @Test
422     public void testGetActivityOptionsWithPAndAboveVersion() {
423         testGetActivityOptions(0, 5, 1);
424     }
425
426     @Test
427     @Config(sdk = 27)
428     public void testGetActivityOptionsWithPBelowVersion() {
429         testGetActivityOptions(-1, 2, -1);
430     }
431
432     private void testGetActivityOptions(int defaultStackId,
433                                         int freeformStackId,
434                                         int stackIdWithoutBrokenApi) {
435         PowerMockito.spy(U.class);
436         BooleanAnswer hasBrokenSetLaunchBoundsApiAnswer = new BooleanAnswer();
437         BooleanAnswer isChromeOsAnswer = new BooleanAnswer();
438         when(U.hasBrokenSetLaunchBoundsApi()).thenAnswer(hasBrokenSetLaunchBoundsApiAnswer);
439         when(U.isChromeOs(context)).thenAnswer(isChromeOsAnswer);
440         boolean originFreeformHackActive = FreeformHackHelper.getInstance().isFreeformHackActive();
441         checkActivityOptionsStackIdForNonContextMenu(
442                 context, null, false, defaultStackId
443         );
444         checkActivityOptionsStackIdForNonContextMenu(
445                 context, ApplicationType.APP_PORTRAIT, false, 1
446         );
447         checkActivityOptionsStackIdForNonContextMenu(
448                 context, ApplicationType.APP_PORTRAIT, true, freeformStackId
449         );
450         checkActivityOptionsStackIdForNonContextMenu(
451                 context, ApplicationType.APP_LANDSCAPE, false, 1
452         );
453         checkActivityOptionsStackIdForNonContextMenu(
454                 context, ApplicationType.APP_LANDSCAPE, true, freeformStackId
455         );
456         checkActivityOptionsStackIdForNonContextMenu(
457                 context, ApplicationType.APP_FULLSCREEN, false, 1
458         );
459         checkActivityOptionsStackIdForNonContextMenu(
460                 context, ApplicationType.FREEFORM_HACK, false, freeformStackId
461         );
462         FreeformHackHelper.getInstance().setFreeformHackActive(originFreeformHackActive);
463         hasBrokenSetLaunchBoundsApiAnswer.answer = true;
464         checkActivityOptionsStackIdForContextMenu(context, 1);
465         hasBrokenSetLaunchBoundsApiAnswer.answer = false;
466         isChromeOsAnswer.answer = false;
467         checkActivityOptionsStackIdForContextMenu(context, stackIdWithoutBrokenApi);
468         isChromeOsAnswer.answer = true;
469         checkActivityOptionsStackIdForContextMenu(context, -1);
470     }
471
472     private void checkActivityOptionsStackIdForContextMenu(Context context,
473                                                            int stackId) {
474         ActivityOptions options = U.getActivityOptions(context, ApplicationType.CONTEXT_MENU, null);
475         assertEquals(stackId, getActivityOptionsStackId(options));
476     }
477
478     private void checkActivityOptionsStackIdForNonContextMenu(Context context,
479                                                               ApplicationType applicationType,
480                                                               boolean isFreeformHackActive,
481                                                               int stackId) {
482         FreeformHackHelper.getInstance().setFreeformHackActive(isFreeformHackActive);
483         ActivityOptions options = U.getActivityOptions(context, applicationType, null);
484         assertEquals(stackId, getActivityOptionsStackId(options));
485     }
486
487     private int getActivityOptionsStackId(ActivityOptions options) {
488         String methodName;
489         if (U.getCurrentApiVersion() >= 28.0f) {
490             methodName = "getLaunchWindowingMode";
491         } else {
492             methodName = "getLaunchStackId";
493         }
494         return ReflectionHelpers.callInstanceMethod(options, methodName);
495     }
496
497     @Test
498     public void testIsChromeOs() {
499         PackageManager packageManager = context.getPackageManager();
500         ShadowPackageManager shadowPackageManager = Shadows.shadowOf(packageManager);
501         shadowPackageManager.setSystemFeature("org.chromium.arc", true);
502         assertTrue(U.isChromeOs(context));
503         shadowPackageManager.setSystemFeature("org.chromium.arc", false);
504         assertFalse(U.isChromeOs(context));
505     }
506
507     @Test
508     @Config(qualifiers = "sw720dp")
509     public void testGetBaseTaskbarSizeWithSW720dp() {
510         PowerMockito.spy(U.class);
511         BooleanAnswer isSystemTrayEnabledAnswer = new BooleanAnswer();
512         when(U.isSystemTrayEnabled(context)).thenAnswer(isSystemTrayEnabledAnswer);
513         isSystemTrayEnabledAnswer.answer = false;
514         // The only difference of the different screen size, is the initial taskbar size.
515         // So we only test the different in this test method.
516         float initialSize = context.getResources().getDimension(R.dimen.tb_base_size_start_plus_divider);
517         initialSize += context.getResources().getDimension(R.dimen.tb_base_size_collapse_button);
518         initialSize += context.getResources().getDimension(R.dimen.tb_dashboard_button_size);
519         assertEquals(Math.round(initialSize), U.getBaseTaskbarSize(context, null));
520     }
521
522     @Test
523     public void testGetBaseTaskbarSizeWithNormalDimension() {
524         PowerMockito.spy(U.class);
525         BooleanAnswer isSystemTrayEnabledAnswer = new BooleanAnswer();
526         when(U.isSystemTrayEnabled(context)).thenAnswer(isSystemTrayEnabledAnswer);
527         isSystemTrayEnabledAnswer.answer = false;
528         float initialSize = context.getResources().getDimension(R.dimen.tb_base_size_start_plus_divider);
529         initialSize += context.getResources().getDimension(R.dimen.tb_base_size_collapse_button);
530         assertEquals(Math.round(initialSize), U.getBaseTaskbarSize(context, null));
531         SharedPreferences prefs = U.getSharedPreferences(context);
532         prefs.edit().putBoolean(PREF_DASHBOARD, true).apply();
533         float dashboardButtonSize =
534                 context.getResources().getDimension(R.dimen.tb_dashboard_button_size);
535         assertEquals(Math.round(initialSize + dashboardButtonSize), U.getBaseTaskbarSize(context, null));
536         prefs.edit().remove(PREF_DASHBOARD).apply();
537         float navbarButtonsMargin =
538                 context.getResources().getDimension(R.dimen.tb_navbar_buttons_margin);
539         float iconSize =
540                 context.getResources().getDimension(R.dimen.tb_icon_size);
541         prefs.edit().putBoolean(PREF_BUTTON_BACK, true).apply();
542         assertEquals(
543                 Math.round(initialSize + navbarButtonsMargin + iconSize),
544                 U.getBaseTaskbarSize(context, null)
545         );
546         prefs.edit().remove(PREF_BUTTON_BACK).apply();
547         prefs.edit().putBoolean(PREF_BUTTON_HOME, true).apply();
548         assertEquals(
549                 Math.round(initialSize + navbarButtonsMargin + iconSize),
550                 U.getBaseTaskbarSize(context, null)
551         );
552         prefs.edit().remove(PREF_BUTTON_HOME).apply();
553         prefs.edit().putBoolean(PREF_BUTTON_RECENTS, true).apply();
554         assertEquals(
555                 Math.round(initialSize + navbarButtonsMargin + iconSize),
556                 U.getBaseTaskbarSize(context, null)
557         );
558         prefs.edit().remove(PREF_BUTTON_RECENTS).apply();
559         isSystemTrayEnabledAnswer.answer = true;
560         float systemTraySize = context.getResources().getDimension(R.dimen.tb_systray_size);
561         assertEquals(Math.round(initialSize + systemTraySize), U.getBaseTaskbarSize(context, null));
562     }
563
564     @Test
565     public void testInitPrefsForBlissOS() {
566         PowerMockito.spy(U.class);
567         when(U.isBlissOs(any(Context.class))).thenReturn(true);
568         assertTrue(U.isBlissOs(context));
569         SharedPreferences prefs = U.getSharedPreferences(context);
570         assertFalse(prefs.getBoolean(PREF_BLISS_OS_PREFS, false));
571         U.initPrefs(context);
572         assertEquals(
573                 PREF_RECENTS_AMOUNT_RUNNING_APPS_ONLY,
574                 prefs.getString(PREF_RECENTS_AMOUNT, "")
575         );
576         assertEquals("0", prefs.getString(PREF_REFRESH_FREQUENCY, ""));
577         assertEquals("2147483647", prefs.getString(PREF_MAX_NUM_OF_RECENTS, ""));
578         assertEquals("true", prefs.getString(PREF_SORT_ORDER, ""));
579         assertEquals(
580                 PREF_START_BUTTON_IMAGE_APP_LOGO,
581                 prefs.getString(PREF_START_BUTTON_IMAGE, "")
582         );
583         assertTrue(prefs.getBoolean(PREF_BUTTON_BACK, false));
584         assertTrue(prefs.getBoolean(PREF_BUTTON_HOME, false));
585         assertTrue(prefs.getBoolean(PREF_BUTTON_RECENTS, false));
586         assertTrue(prefs.getBoolean(PREF_AUTO_HIDE_NAVBAR, false));
587         assertFalse(prefs.getBoolean(PREF_SHORTCUT_ICON, true));
588         assertTrue(prefs.getBoolean(PREF_BLISS_OS_PREFS, false));
589         prefs.edit().putBoolean(PREF_BLISS_OS_PREFS, false);
590     }
591
592     @Test
593     public void testInitPrefsForNormalWithCanEnableFreeformAndHackOverrideFalse() {
594         PowerMockito.spy(U.class);
595         when(U.canEnableFreeform()).thenReturn(true);
596         SharedPreferences prefs = U.getSharedPreferences(context);
597         prefs.edit().putBoolean(PREF_FREEFORM_HACK_OVERRIDE, false).apply();
598         U.initPrefs(context);
599         assertEquals(
600                 U.hasFreeformSupport(context) && !U.isSamsungDevice(),
601                 prefs.getBoolean(PREF_FREEFORM_HACK, false)
602         );
603         assertFalse(prefs.getBoolean(PREF_SAVE_WINDOW_SIZES, true));
604         assertTrue(prefs.getBoolean(PREF_FREEFORM_HACK_OVERRIDE, false));
605     }
606
607     @Test
608     public void testInitPrefsForNormalWithCanEnableFreeformAndHackOverrideTrueButNoSupport() {
609         PowerMockito.spy(U.class);
610         when(U.canEnableFreeform()).thenReturn(true);
611         SharedPreferences prefs = U.getSharedPreferences(context);
612         prefs.edit().putBoolean(PREF_FREEFORM_HACK_OVERRIDE, true).apply();
613         when(U.hasFreeformSupport(context)).thenReturn(false);
614         U.initPrefs(context);
615         assertFalse(prefs.getBoolean(PREF_FREEFORM_HACK, false));
616     }
617
618     @Test
619     public void testInitPrefsForNormalWithCantEnableFreeform() {
620         PowerMockito.spy(U.class);
621         when(U.canEnableFreeform()).thenReturn(false);
622         SharedPreferences prefs = U.getSharedPreferences(context);
623         U.initPrefs(context);
624         assertFalse(prefs.getBoolean(PREF_FREEFORM_HACK, false));
625         prefs.edit()
626                 .putBoolean(PREF_FREEFORM_HACK, false)
627                 .putBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false)
628                 .apply();
629         U.initPrefs(context);
630         assertFalse(prefs.getBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false));
631         prefs.edit()
632                 .putBoolean(PREF_FREEFORM_HACK, true)
633                 .putBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false)
634                 .apply();
635         U.initPrefs(context);
636         assertTrue(prefs.getBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false));
637         prefs.edit()
638                 .putBoolean(PREF_FREEFORM_HACK, false)
639                 .putBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, true)
640                 .apply();
641         U.initPrefs(context);
642         assertTrue(prefs.getBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false));
643         prefs.edit()
644                 .putBoolean(PREF_FREEFORM_HACK, true)
645                 .putBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, true)
646                 .apply();
647         U.initPrefs(context);
648         assertTrue(prefs.getBoolean(PREF_SHOW_FREEFORM_DISABLED_MESSAGE, false));
649     }
650
651     @Test
652     public void testIsOverridingFreeformHackForPAndAboveVersion() {
653         PowerMockito.spy(U.class);
654         when(U.isChromeOs(context)).thenReturn(false);
655         // Check preferences
656         assertFalse(U.isOverridingFreeformHack(context, true));
657         SharedPreferences prefs = U.getSharedPreferences(context);
658         prefs.edit().putBoolean(PREF_FREEFORM_HACK, true).apply();
659         assertTrue(U.isOverridingFreeformHack(context, true));
660         prefs.edit().remove(PREF_FREEFORM_HACK).apply();
661
662         // Don't check preferences
663         assertTrue(U.isOverridingFreeformHack(context, false));
664     }
665
666     @Test
667     @Config(sdk = 27)
668     public void testIsOverridingFreeformHackForPBelowVersion() {
669         PowerMockito.spy(U.class);
670         when(U.isChromeOs(context)).thenReturn(false);
671         // Check preferences
672         assertFalse(U.isOverridingFreeformHack(context, true));
673         SharedPreferences prefs = U.getSharedPreferences(context);
674         prefs.edit().putBoolean(PREF_FREEFORM_HACK, true).apply();
675         assertFalse(U.isOverridingFreeformHack(context, true));
676         prefs.edit().remove(PREF_FREEFORM_HACK).apply();
677
678         // Don't check preferences
679         assertFalse(U.isOverridingFreeformHack(context, false));
680     }
681
682     @Test
683     public void testIsOverridingFreeformHackForChromeOS() {
684         PowerMockito.spy(U.class);
685         when(U.isChromeOs(context)).thenReturn(true);
686         // Check preferences
687         assertFalse(U.isOverridingFreeformHack(context, true));
688         SharedPreferences prefs = U.getSharedPreferences(context);
689         prefs.edit().putBoolean(PREF_FREEFORM_HACK, true).apply();
690         // The default PREF_CHROME_OS_CONTEXT_MENU_FIX is true
691         assertTrue(U.isOverridingFreeformHack(context, true));
692         prefs.edit().putBoolean(PREF_CHROME_OS_CONTEXT_MENU_FIX, false).apply();
693         assertFalse(U.isOverridingFreeformHack(context, true));
694         prefs.edit().putBoolean(PREF_CHROME_OS_CONTEXT_MENU_FIX, true).apply();
695         assertTrue(U.isOverridingFreeformHack(context, true));
696         prefs.edit().remove(PREF_FREEFORM_HACK).apply();
697         prefs.edit().remove(PREF_CHROME_OS_CONTEXT_MENU_FIX).apply();
698
699         // Don't check preferences
700         assertTrue(U.isOverridingFreeformHack(context, false));
701         prefs.edit().putBoolean(PREF_CHROME_OS_CONTEXT_MENU_FIX, false).apply();
702         assertFalse(U.isOverridingFreeformHack(context, false));
703         prefs.edit().putBoolean(PREF_CHROME_OS_CONTEXT_MENU_FIX, true).apply();
704         assertTrue(U.isOverridingFreeformHack(context, false));
705         prefs.edit().remove(PREF_CHROME_OS_CONTEXT_MENU_FIX).apply();
706     }
707
708     @Test
709     @Config(sdk = 25)
710     public void testHasBrokenSetLaunchBoundsApiForApi25() {
711         assertFalse(U.hasBrokenSetLaunchBoundsApi());
712     }
713
714     @Test
715     @Config(sdk = 26)
716     public void testHasBrokenSetLaunchBoundsApiForApi26() throws Exception {
717         testHasBrokenSetLaunchBoundsApiWithValidApiVersion();
718     }
719
720     @Test
721     @Config(sdk = 27)
722     public void testHasBrokenSetLaunchBoundsApiForApi27() throws Exception {
723         testHasBrokenSetLaunchBoundsApiWithValidApiVersion();
724         testHasBrokenSetLaunchBoundsApiWithValidApiVersion();
725     }
726
727     @Test
728     @Config(sdk = 28)
729     public void testHasBrokenSetLaunchBoundsApiForApi28() {
730         assertFalse(U.hasBrokenSetLaunchBoundsApi());
731     }
732
733     private void testHasBrokenSetLaunchBoundsApiWithValidApiVersion() throws Exception {
734         PowerMockito.spy(U.class);
735         BooleanAnswer isSamsungDeviceAnswer = new BooleanAnswer();
736         BooleanAnswer isNvidiaDevice = new BooleanAnswer();
737         when(U.isSamsungDevice()).thenAnswer(isSamsungDeviceAnswer);
738         when(U.class, "isNvidiaDevice").thenAnswer(isNvidiaDevice);
739         isSamsungDeviceAnswer.answer = false;
740         isNvidiaDevice.answer = false;
741         assertTrue(U.hasBrokenSetLaunchBoundsApi());
742         isSamsungDeviceAnswer.answer = false;
743         isNvidiaDevice.answer = true;
744         assertFalse(U.hasBrokenSetLaunchBoundsApi());
745         isSamsungDeviceAnswer.answer = true;
746         isNvidiaDevice.answer = false;
747         assertFalse(U.hasBrokenSetLaunchBoundsApi());
748         isSamsungDeviceAnswer.answer = true;
749         isNvidiaDevice.answer = true;
750         assertFalse(U.hasBrokenSetLaunchBoundsApi());
751     }
752
753     @Test
754     public void testWrapContext() {
755         SharedPreferences prefs = U.getSharedPreferences(context);
756         prefs.edit().putString(PREF_THEME, "light").apply();
757         Context newContext = U.wrapContext(context);
758         Integer themeResource = ReflectionHelpers.getField(newContext, "mThemeResource");
759         assertNotNull(themeResource);
760         assertEquals(R.style.Taskbar, (int) themeResource);
761         prefs.edit().putString(PREF_THEME, "dark").apply();
762         newContext = U.wrapContext(context);
763         themeResource = ReflectionHelpers.getField(newContext, "mThemeResource");
764         assertNotNull(themeResource);
765         assertEquals(R.style.Taskbar_Dark, (int) themeResource);
766         prefs.edit().putString(PREF_THEME, "non-support").apply();
767         newContext = U.wrapContext(context);
768         assertTrue(newContext instanceof ContextThemeWrapper);
769         prefs.edit().remove(PREF_THEME).apply();
770         newContext = U.wrapContext(context);
771         themeResource = ReflectionHelpers.getField(newContext, "mThemeResource");
772         assertNotNull(themeResource);
773         assertEquals(R.style.Taskbar, (int) themeResource);
774     }
775
776     @Test
777     public void testEnableFreeformModeShortcut() {
778         PowerMockito.spy(U.class);
779         BooleanAnswer canEnableFreeformAnswer = new BooleanAnswer();
780         BooleanAnswer isOverridingFreeformHackAnswer = new BooleanAnswer();
781         BooleanAnswer isChromeOsAnswer = new BooleanAnswer();
782         when(U.canEnableFreeform()).thenAnswer(canEnableFreeformAnswer);
783         when(U.isOverridingFreeformHack(context, false))
784                 .thenAnswer(isOverridingFreeformHackAnswer);
785         when(U.isChromeOs(context)).thenAnswer(isChromeOsAnswer);
786
787         canEnableFreeformAnswer.answer = false;
788         isOverridingFreeformHackAnswer.answer = false;
789         isChromeOsAnswer.answer = false;
790         assertFalse(U.enableFreeformModeShortcut(context));
791
792         canEnableFreeformAnswer.answer = false;
793         isOverridingFreeformHackAnswer.answer = false;
794         isChromeOsAnswer.answer = true;
795         assertFalse(U.enableFreeformModeShortcut(context));
796
797         canEnableFreeformAnswer.answer = false;
798         isOverridingFreeformHackAnswer.answer = true;
799         isChromeOsAnswer.answer = false;
800         assertFalse(U.enableFreeformModeShortcut(context));
801
802         canEnableFreeformAnswer.answer = false;
803         isOverridingFreeformHackAnswer.answer = true;
804         isChromeOsAnswer.answer = true;
805         assertFalse(U.enableFreeformModeShortcut(context));
806
807         canEnableFreeformAnswer.answer = true;
808         isOverridingFreeformHackAnswer.answer = false;
809         isChromeOsAnswer.answer = false;
810         assertTrue(U.enableFreeformModeShortcut(context));
811
812         canEnableFreeformAnswer.answer = true;
813         isOverridingFreeformHackAnswer.answer = false;
814         isChromeOsAnswer.answer = true;
815         assertFalse(U.enableFreeformModeShortcut(context));
816
817         canEnableFreeformAnswer.answer = true;
818         isOverridingFreeformHackAnswer.answer = true;
819         isChromeOsAnswer.answer = false;
820         assertFalse(U.enableFreeformModeShortcut(context));
821
822         canEnableFreeformAnswer.answer = true;
823         isOverridingFreeformHackAnswer.answer = true;
824         isChromeOsAnswer.answer = true;
825         assertFalse(U.enableFreeformModeShortcut(context));
826     }
827
828     @Test
829     @Config(sdk = 26)
830     public void testGetOverlayTypeForOAndAboveVersion() {
831         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, U.getOverlayType());
832     }
833
834     @Test
835     @Config(sdk = 25)
836     public void testGetOverlayTypeForOBelowVersion() {
837         assertEquals(WindowManager.LayoutParams.TYPE_PHONE, U.getOverlayType());
838     }
839
840     @Test
841     public void testGetDefaultStartButtonImage() {
842         SharedPreferences prefs = U.getSharedPreferences(context);
843         prefs.edit().putBoolean(PREF_APP_DRAWER_ICON, true).apply();
844         assertEquals(PREF_START_BUTTON_IMAGE_APP_LOGO, U.getDefaultStartButtonImage(context));
845         prefs.edit().putBoolean(PREF_APP_DRAWER_ICON, false).apply();
846         assertEquals(PREF_START_BUTTON_IMAGE_DEFAULT, U.getDefaultStartButtonImage(context));
847         prefs.edit().remove(PREF_APP_DRAWER_ICON).apply();
848         assertEquals(PREF_START_BUTTON_IMAGE_DEFAULT, U.getDefaultStartButtonImage(context));
849     }
850
851     @Test
852     public void testIsDesktopIconEnabled() throws Exception {
853         PowerMockito.spy(U.class);
854         BooleanAnswer canBootToFreeformAnswer = new BooleanAnswer();
855         BooleanAnswer shouldLaunchTouchAbsorberAnswer = new BooleanAnswer();
856         when(U.class, "canBootToFreeform", context, false)
857                 .thenAnswer(canBootToFreeformAnswer);
858         when(U.class, "shouldLaunchTouchAbsorber", context)
859                 .thenAnswer(shouldLaunchTouchAbsorberAnswer);
860
861         canBootToFreeformAnswer.answer = false;
862         shouldLaunchTouchAbsorberAnswer.answer = false;
863         assertTrue(U.isDesktopIconsEnabled(context));
864
865         canBootToFreeformAnswer.answer = false;
866         shouldLaunchTouchAbsorberAnswer.answer = true;
867         assertFalse(U.isDesktopIconsEnabled(context));
868
869         canBootToFreeformAnswer.answer = true;
870         shouldLaunchTouchAbsorberAnswer.answer = false;
871         assertFalse(U.isDesktopIconsEnabled(context));
872
873         canBootToFreeformAnswer.answer = true;
874         shouldLaunchTouchAbsorberAnswer.answer = true;
875         assertFalse(U.isDesktopIconsEnabled(context));
876     }
877
878     @Test
879     @Config(sdk = 22)
880     public void testIsSystemTrayEnabledForMBelowVersion() {
881         SharedPreferences prefs = U.getSharedPreferences(context);
882         prefs.edit()
883                 .putBoolean(PREF_SYS_TRAY, true)
884                 .putBoolean(PREF_FULL_LENGTH, true)
885                 .apply();
886         assertFalse(U.isSystemTrayEnabled(context));
887         prefs.edit().remove(PREF_SYS_TRAY).remove(PREF_FULL_LENGTH).apply();
888     }
889
890     @Test
891     public void testIsSystemTrayEnabledForMAndAboveVersion() {
892         SharedPreferences prefs = U.getSharedPreferences(context);
893         assertFalse(U.isSystemTrayEnabled(context));
894         prefs.edit().putBoolean(PREF_SYS_TRAY, true).apply();
895         assertTrue(U.isSystemTrayEnabled(context));
896         prefs.edit().putBoolean(PREF_FULL_LENGTH, false).apply();
897         assertFalse(U.isSystemTrayEnabled(context));
898         prefs.edit().putBoolean(PREF_FULL_LENGTH, true).apply();
899         assertTrue(U.isSystemTrayEnabled(context));
900         prefs.edit()
901                 .putString(PREF_POSITION, POSITION_BOTTOM_VERTICAL_LEFT)
902                 .putBoolean(PREF_ANCHOR, false)
903                 .apply();
904         assertFalse(U.isSystemTrayEnabled(context));
905         prefs.edit().remove(PREF_POSITION).remove(PREF_ANCHOR).apply();
906     }
907
908     @Test
909     public void testApplyDisplayCutoutModeToWithPAndAboveVersion() {
910         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
911         assertTrue(U.applyDisplayCutoutModeTo(layoutParams));
912         assertEquals(
913                 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,
914                 layoutParams.layoutInDisplayCutoutMode
915         );
916     }
917
918     @Test
919     @Config(sdk = 27)
920     public void testApplyDisplayCutoutModeToWithBelowVersion() {
921         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
922         assertFalse(U.applyDisplayCutoutModeTo(layoutParams));
923     }
924
925     @Test
926     public void testIsDesktopModeActive() {
927         PowerMockito.spy(U.class);
928         BooleanAnswer isDesktopModeSupportedAnswer = new BooleanAnswer();
929         IntAnswer getExternalDisplayIdAnswer = new IntAnswer();
930         BooleanAnswer hasFreeformSupportAnswer = new BooleanAnswer();
931         when(U.isDesktopModeSupported(context)).thenAnswer(isDesktopModeSupportedAnswer);
932         when(U.getExternalDisplayID(context)).thenAnswer(getExternalDisplayIdAnswer);
933         when(U.hasFreeformSupport(context)).thenAnswer(hasFreeformSupportAnswer);
934
935         isDesktopModeSupportedAnswer.answer = false;
936         assertFalse(U.isDesktopModeActive(context));
937
938         isDesktopModeSupportedAnswer.answer = true;
939         Settings.Global.putInt(
940                 context.getContentResolver(),
941                 "force_desktop_mode_on_external_displays",
942                 0
943         );
944         assertFalse(U.isDesktopModeActive(context));
945         Settings.Global.putInt(
946                 context.getContentResolver(),
947                 "force_desktop_mode_on_external_displays",
948                 1
949         );
950         assertFalse(U.isDesktopModeActive(context));
951         getExternalDisplayIdAnswer.answer = 1;
952         assertFalse(U.isDesktopModeActive(context));
953         hasFreeformSupportAnswer.answer = true;
954         assertTrue(U.isDesktopModeActive(context));
955         Settings.Global.putInt(
956                 context.getContentResolver(),
957                 "force_desktop_mode_on_external_displays",
958                 0
959         );
960     }
961
962     @Test
963     public void testSendBroadcast() {
964         TestBroadcastReceiver receiver = new TestBroadcastReceiver();
965         IntentFilter filter = new IntentFilter(TestBroadcastReceiver.ACTION);
966         LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter);
967         U.sendBroadcast(context, TestBroadcastReceiver.ACTION);
968         assertTrue(receiver.onReceived);
969         receiver.onReceived = false;
970         U.sendBroadcast(context, new Intent(TestBroadcastReceiver.ACTION));
971         assertTrue(receiver.onReceived);
972     }
973
974     private static final class TestBroadcastReceiver extends BroadcastReceiver {
975         private static final String ACTION = "test-broadcast-receiver-action";
976         private boolean onReceived;
977
978         @Override
979         public void onReceive(Context context, Intent intent) {
980             if (intent == null || !ACTION.equals(intent.getAction())) {
981                 return;
982             }
983             onReceived = true;
984         }
985     }
986 }