1 /*
2  * Copyright (C) 2016 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 
17 package com.android.documentsui;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertSame;
22 import static org.junit.Assert.assertTrue;
23 
24 import android.content.ComponentCallbacks2;
25 import android.graphics.Bitmap;
26 import android.graphics.Point;
27 import android.net.Uri;
28 import android.support.test.filters.SmallTest;
29 import android.support.test.runner.AndroidJUnit4;
30 
31 import com.android.documentsui.ThumbnailCache.Result;
32 import com.android.documentsui.testing.Bitmaps;
33 
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 
38 @RunWith(AndroidJUnit4.class)
39 @SmallTest
40 public class ThumbnailCacheTest {
41 
42     private static final Uri URI_0 = Uri.parse("content://authority/document/0");
43     private static final Uri URI_1 = Uri.parse("content://authority/document/1");
44 
45     private static final Point SMALL_SIZE = new Point(1, 1);
46     private static final Point MID_SIZE = new Point(2, 2);
47     private static final Point LARGE_SIZE = new Point(3, 3);
48 
49     private static final Bitmap SMALL_BITMAP = Bitmaps.createTestBitmap(1, 1);
50     private static final Bitmap MIDSIZE_BITMAP = Bitmaps.createTestBitmap(2, 2);
51     private static final Bitmap LARGE_BITMAP = Bitmaps.createTestBitmap(3, 3);
52 
53     private static final long LAST_MODIFIED = 100;
54 
55     private static final int CACHE_SIZE_LIMIT =
56             MIDSIZE_BITMAP.getByteCount() + LARGE_BITMAP.getByteCount();
57 
58     private ThumbnailCache mCache;
59 
60     @Before
setUp()61     public void setUp() {
62         mCache = new ThumbnailCache(CACHE_SIZE_LIMIT);
63     }
64 
65     @Test
testMiss()66     public void testMiss() {
67         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
68 
69         Result result = mCache.getThumbnail(URI_1, MID_SIZE);
70 
71         assertMiss(result);
72     }
73 
74     @Test
testHit_Exact()75     public void testHit_Exact() {
76         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
77 
78         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
79 
80         assertHitExact(result);
81         assertSame(MIDSIZE_BITMAP, result.getThumbnail());
82     }
83 
84     @Test
testHit_Smaller()85     public void testHit_Smaller() {
86         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
87 
88         Result result = mCache.getThumbnail(URI_0, LARGE_SIZE);
89 
90         assertHitSmaller(result);
91         assertSame(MIDSIZE_BITMAP, result.getThumbnail());
92     }
93 
94     @Test
testHit_Larger()95     public void testHit_Larger() {
96         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
97 
98         Result result = mCache.getThumbnail(URI_0, SMALL_SIZE);
99 
100         assertHitLarger(result);
101         assertSame(MIDSIZE_BITMAP, result.getThumbnail());
102     }
103 
104     @Test
testHit_Larger_HasBothSize()105     public void testHit_Larger_HasBothSize() {
106         mCache.putThumbnail(URI_0, LARGE_SIZE, LARGE_BITMAP, LAST_MODIFIED);
107         mCache.putThumbnail(URI_0, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
108 
109         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
110 
111         assertHitLarger(result);
112         assertSame(LARGE_BITMAP, result.getThumbnail());
113     }
114 
115     @Test
testHit_Exact_MultiplePut()116     public void testHit_Exact_MultiplePut() {
117         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
118 
119         Bitmap localBitmap = Bitmaps.createTestBitmap(MID_SIZE.x, MID_SIZE.y);
120         long localLastModified = LAST_MODIFIED + 100;
121         mCache.putThumbnail(URI_0, MID_SIZE, localBitmap, localLastModified);
122 
123         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
124 
125         assertHitExact(result);
126         assertSame(localBitmap, result.getThumbnail());
127     }
128 
129     @Test
testHit_EqualLastModified()130     public void testHit_EqualLastModified() {
131         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
132 
133         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
134 
135         assertEquals(LAST_MODIFIED, result.getLastModified());
136     }
137 
138     @Test
testEvictOldest_SizeExceeded()139     public void testEvictOldest_SizeExceeded() {
140         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
141         mCache.putThumbnail(URI_1, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
142         mCache.putThumbnail(URI_1, LARGE_SIZE, LARGE_BITMAP, LAST_MODIFIED);
143 
144         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
145 
146         assertMiss(result);
147     }
148 
149     @Test
testCacheShrink_OnTrimMemory_Moderate()150     public void testCacheShrink_OnTrimMemory_Moderate() {
151         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
152         mCache.putThumbnail(URI_0, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
153         mCache.putThumbnail(URI_0, LARGE_SIZE, LARGE_BITMAP, LAST_MODIFIED);
154 
155         mCache.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
156 
157         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
158         assertMiss(result);
159     }
160 
161     @Test
testCacheShrink_OnTrimMemory_Background()162     public void testCacheShrink_OnTrimMemory_Background() {
163         mCache.putThumbnail(URI_0, LARGE_SIZE, LARGE_BITMAP, LAST_MODIFIED);
164         mCache.putThumbnail(URI_0, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
165 
166         mCache.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
167 
168         // Math here (size of each pixel omitted):
169         // Limit = midSize + largeSize = 2 * 2 + 3 * 3 = 13, so after all putThumbnail the cache is
170         // full.
171         //
172         // HalfLimit = Limit / 2 = 5. After evicting largeSize bitmap, cache size decreases to 4,
173         // which is smaller than 5. Then smallSize bitmap remains.
174         Result result = mCache.getThumbnail(URI_0, MID_SIZE);
175         assertHitSmaller(result);
176         assertSame(SMALL_BITMAP, result.getThumbnail());
177     }
178 
179     @Test
testRemoveUri()180     public void testRemoveUri() {
181         mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
182         mCache.putThumbnail(URI_0, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
183         mCache.putThumbnail(URI_1, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
184 
185         mCache.removeUri(URI_0);
186 
187         assertMiss(mCache.getThumbnail(URI_0, MID_SIZE));
188         assertHitExact(mCache.getThumbnail(URI_1, MID_SIZE));
189     }
190 
assertMiss(Result result)191     private static void assertMiss(Result result) {
192         assertEquals(Result.CACHE_MISS, result.getStatus());
193         assertFalse(result.isExactHit());
194         assertFalse(result.isHit());
195     }
196 
assertHitExact(Result result)197     private static void assertHitExact(Result result) {
198         assertEquals(Result.CACHE_HIT_EXACT, result.getStatus());
199         assertTrue(result.isExactHit());
200         assertTrue(result.isHit());
201     }
202 
assertHitSmaller(Result result)203     private static void assertHitSmaller(Result result) {
204         assertEquals(Result.CACHE_HIT_SMALLER, result.getStatus());
205         assertFalse(result.isExactHit());
206         assertTrue(result.isHit());
207     }
208 
assertHitLarger(Result result)209     private static void assertHitLarger(Result result) {
210         assertEquals(Result.CACHE_HIT_LARGER, result.getStatus());
211         assertFalse(result.isExactHit());
212         assertTrue(result.isHit());
213     }
214 }
215