1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settingslib.suggestions;
18
19import static com.google.common.truth.Truth.assertThat;
20import static org.robolectric.RuntimeEnvironment.application;
21import static org.robolectric.shadow.api.Shadow.extract;
22
23import android.content.ComponentName;
24import android.content.Intent;
25import android.content.SharedPreferences;
26import android.content.pm.ResolveInfo;
27import android.os.Bundle;
28import android.preference.PreferenceManager;
29
30import com.android.settingslib.SettingsLibRobolectricTestRunner;
31import com.android.settingslib.drawer.Tile;
32import com.android.settingslib.drawer.TileUtilsTest;
33
34import org.junit.Before;
35import org.junit.Test;
36import org.junit.runner.RunWith;
37import org.robolectric.shadows.ShadowPackageManager;
38
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.List;
42
43@RunWith(SettingsLibRobolectricTestRunner.class)
44public class SuggestionParserTest {
45
46    private ShadowPackageManager mPackageManager;
47    private SuggestionParser mSuggestionParser;
48    private SuggestionCategory mMultipleCategory;
49    private SuggestionCategory mExclusiveCategory;
50    private SuggestionCategory mExpiredExclusiveCategory;
51    private List<Tile> mSuggestionsBeforeDismiss;
52    private List<Tile> mSuggestionsAfterDismiss;
53    private SharedPreferences mPrefs;
54    private Tile mSuggestion;
55
56    @Before
57    public void setUp() {
58        mPackageManager = extract(application.getPackageManager());
59        mPrefs = PreferenceManager.getDefaultSharedPreferences(application);
60        mSuggestion = new Tile();
61        mSuggestion.intent = new Intent("action");
62        mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
63        mSuggestion.metaData = new Bundle();
64        mMultipleCategory = new SuggestionCategory();
65        mMultipleCategory.category = "category1";
66        mMultipleCategory.multiple = true;
67        mExclusiveCategory = new SuggestionCategory();
68        mExclusiveCategory.category = "category2";
69        mExclusiveCategory.exclusive = true;
70        mExpiredExclusiveCategory = new SuggestionCategory();
71        mExpiredExclusiveCategory.category = "category3";
72        mExpiredExclusiveCategory.exclusive = true;
73        mExpiredExclusiveCategory.exclusiveExpireDaysInMillis = 0;
74
75        mSuggestionParser = new SuggestionParser(application, mPrefs,
76                Arrays.asList(mMultipleCategory, mExclusiveCategory, mExpiredExclusiveCategory),
77                "0");
78
79        ResolveInfo info1 = TileUtilsTest.newInfo(true, null);
80        info1.activityInfo.packageName = "pkg";
81        ResolveInfo infoDupe1 = TileUtilsTest.newInfo(true, null);
82        infoDupe1.activityInfo.packageName = "pkg";
83
84        ResolveInfo info2 = TileUtilsTest.newInfo(true, null);
85        info2.activityInfo.packageName = "pkg2";
86        ResolveInfo info3 = TileUtilsTest.newInfo(true, null);
87        info3.activityInfo.packageName = "pkg3";
88        ResolveInfo info4 = TileUtilsTest.newInfo(true, null);
89        info4.activityInfo.packageName = "pkg4";
90
91        Intent intent1 = new Intent(Intent.ACTION_MAIN).addCategory("category1");
92        Intent intent2 = new Intent(Intent.ACTION_MAIN).addCategory("category2");
93        Intent intent3 = new Intent(Intent.ACTION_MAIN).addCategory("category3");
94
95        mPackageManager.addResolveInfoForIntent(intent1, info1);
96        mPackageManager.addResolveInfoForIntent(intent1, info2);
97        mPackageManager.addResolveInfoForIntent(intent1, infoDupe1);
98        mPackageManager.addResolveInfoForIntent(intent2, info3);
99        mPackageManager.addResolveInfoForIntent(intent3, info4);
100    }
101
102    @Test
103    public void dismissSuggestion_shouldDismiss() {
104        assertThat(mSuggestionParser.dismissSuggestion(mSuggestion)).isTrue();
105    }
106
107    @Test
108    public void testGetSuggestions_withoutSmartSuggestions_shouldDismiss() {
109        readAndDismissSuggestion(false);
110        mSuggestionParser.readSuggestions(mMultipleCategory, mSuggestionsAfterDismiss, false);
111        assertThat(mSuggestionsBeforeDismiss).hasSize(2);
112        assertThat(mSuggestionsAfterDismiss).hasSize(1);
113        assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
114    }
115
116    @Test
117    public void testGetSuggestions_withSmartSuggestions_shouldDismiss() {
118        readAndDismissSuggestion(true);
119        assertThat(mSuggestionsBeforeDismiss).hasSize(2);
120        assertThat(mSuggestionsAfterDismiss).hasSize(1);
121    }
122
123    @Test
124    public void testGetSuggestion_exclusiveNotAvailable_onlyRegularCategoryAndNoDupe() {
125        mPackageManager.removeResolveInfosForIntent(
126                new Intent(Intent.ACTION_MAIN).addCategory("category2"),
127                "pkg3");
128        mPackageManager.removeResolveInfosForIntent(
129                new Intent(Intent.ACTION_MAIN).addCategory("category3"),
130                "pkg4");
131
132        // If exclusive item is not available, the other categories should be shown
133        final SuggestionList sl =
134                mSuggestionParser.getSuggestions(false /* isSmartSuggestionEnabled */);
135        final List<Tile> suggestions = sl.getSuggestions();
136        assertThat(suggestions).hasSize(2);
137
138        assertThat(suggestions.get(0).intent.getComponent().getPackageName()).isEqualTo("pkg");
139        assertThat(suggestions.get(1).intent.getComponent().getPackageName()).isEqualTo("pkg2");
140    }
141
142    @Test
143    public void testGetSuggestion_exclusiveExpiredAvailable_shouldLoadWithRegularCategory() {
144        // First remove permanent exclusive
145        mPackageManager.removeResolveInfosForIntent(
146                new Intent(Intent.ACTION_MAIN).addCategory("category2"),
147                "pkg3");
148        // Set the other exclusive to be expired.
149        mPrefs.edit()
150                .putLong(mExpiredExclusiveCategory.category + "_setup_time",
151                        System.currentTimeMillis() - 1000)
152                .commit();
153
154        // If exclusive is expired, they should be shown together with the other categories
155        final SuggestionList sl =
156                mSuggestionParser.getSuggestions(true /* isSmartSuggestionEnabled */);
157        final List<Tile> suggestions = sl.getSuggestions();
158
159        assertThat(suggestions).hasSize(3);
160    }
161
162    @Test
163    public void testGetSuggestions_exclusive() {
164        final SuggestionList sl =
165                mSuggestionParser.getSuggestions(false /* isSmartSuggestionEnabled */);
166        final List<Tile> suggestions = sl.getSuggestions();
167
168        assertThat(suggestions).hasSize(1);
169    }
170
171    @Test
172    public void isSuggestionDismissed_dismissedSuggestion_shouldReturnTrue() {
173        final Tile suggestion = new Tile();
174        suggestion.metaData = new Bundle();
175        suggestion.metaData.putString(SuggestionParser.META_DATA_DISMISS_CONTROL, "1,2,3");
176        suggestion.intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
177
178        // Dismiss suggestion when smart suggestion is not enabled.
179        mSuggestionParser.dismissSuggestion(suggestion);
180
181        assertThat(mSuggestionParser.isDismissed(suggestion, true /* isSmartSuggestionEnabled */))
182                .isTrue();
183    }
184
185    private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
186        mSuggestionsBeforeDismiss = new ArrayList<>();
187        mSuggestionsAfterDismiss = new ArrayList<>();
188        mSuggestionParser.readSuggestions(
189                mMultipleCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
190
191        final Tile suggestion = mSuggestionsBeforeDismiss.get(0);
192        if (mSuggestionParser.dismissSuggestion(suggestion)) {
193            mPackageManager.removeResolveInfosForIntent(
194                    new Intent(Intent.ACTION_MAIN).addCategory(mMultipleCategory.category),
195                    suggestion.intent.getComponent().getPackageName());
196        }
197        mSuggestionParser.readSuggestions(
198                mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
199    }
200}
201