Skip to content

Commit f9b3dba

Browse files
committed
Pull logic into DeviceIconManager and use listener
1 parent 8f0062e commit f9b3dba

5 files changed

Lines changed: 76 additions & 166 deletions

File tree

android/hello_sdl_android/src/main/AndroidManifest.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
android:icon="@mipmap/ic_launcher"
1818
android:label="@string/app_name"
1919
android:theme="@style/AppTheme"
20-
android:usesCleartextTraffic="true"
2120
tools:ignore="DeepLinks">
2221
<activity
2322
android:name=".MainActivity"

android/sdl_android/src/androidTest/AndroidManifest.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1414

1515
<application
16-
android:debuggable="true"
17-
android:usesCleartextTraffic="true">
16+
android:debuggable="true">
1817
<uses-library android:name="android.test.runner" />
1918
</application>
2019

android/sdl_android/src/androidTest/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManagerTests.java

Lines changed: 24 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.security.MessageDigest;
1919
import java.security.NoSuchAlgorithmException;
2020

21+
import static org.mockito.ArgumentMatchers.any;
2122
import static org.mockito.ArgumentMatchers.anyInt;
2223
import static org.mockito.ArgumentMatchers.anyString;
2324
import static org.mockito.ArgumentMatchers.isNull;
@@ -28,7 +29,7 @@ public class LockScreenDeviceIconManagerTests extends AndroidTestCase2 {
2829

2930
TemporaryFolder tempFolder = new TemporaryFolder();
3031
private LockScreenDeviceIconManager lockScreenDeviceIconManager;
31-
private static final String ICON_URL = "http://i.imgur.com/TgkvOIZ.png";
32+
private static final String ICON_URL = "https://i.imgur.com/TgkvOIZ.png";
3233
private static final String LAST_UPDATED_TIME = "lastUpdatedTime";
3334
private static final String STORED_PATH = "storedPath";
3435

@@ -40,178 +41,63 @@ public void tearDown() throws Exception {
4041
super.tearDown();
4142
}
4243

43-
public void testUpdateCacheImageShouldReturnTrueWhenSharedPreferencesDoesNotExist() {
44+
public void testRetrieveIconShouldCallOnErrorAndOnImageRetrievedWithNullWhenGivenURLThatCannotDownloadAndIconIsNotCached() {
4445
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
4546
final Context context = Mockito.mock(Context.class);
47+
final LockScreenDeviceIconManager.OnIconRetrievedListener listener = Mockito.mock(LockScreenDeviceIconManager.OnIconRetrievedListener.class);
48+
4649
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
4750
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(null);
4851

4952
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
50-
boolean imageUpToDate = lockScreenDeviceIconManager.isIconCachedAndValid(ICON_URL);
51-
assertFalse(imageUpToDate);
53+
lockScreenDeviceIconManager.retrieveIcon("", listener);
54+
verify(listener, times(1)).onError(anyString());
55+
verify(listener, times(1)).onImageRetrieved(null);
5256
}
5357

54-
public void testUpdateCacheImageShouldReturnTrueWhenUnableToReadSharedPreference() {
58+
public void testRetrieveIconShouldCallOnImageOnImageRetrievedWithIconWhenIconUpdateTimeIsNullFromSharedPref() {
5559
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
56-
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
5760
final Context context = Mockito.mock(Context.class);
58-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
59-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn("");
60-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
61-
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
62-
Mockito.when(sharedPrefsEditor.remove(anyString())).thenReturn(sharedPrefsEditor);
63-
Mockito.when(sharedPrefsEditor.commit()).thenReturn(true);
64-
65-
66-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
67-
boolean imageUpToDate = lockScreenDeviceIconManager.isIconCachedAndValid(ICON_URL);
68-
assertFalse(imageUpToDate);
69-
}
61+
final LockScreenDeviceIconManager.OnIconRetrievedListener listener = Mockito.mock(LockScreenDeviceIconManager.OnIconRetrievedListener.class);
7062

71-
public void testUpdateCacheImageShouldReturnTrueSharedPreferenceReturnsAnOutdatedIcon() {
72-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
73-
final Context context = Mockito.mock(Context.class);
7463
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
75-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(35));
64+
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(null);
7665

7766
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
78-
boolean imageUpToDate = lockScreenDeviceIconManager.isIconCachedAndValid(ICON_URL);
79-
assertFalse(imageUpToDate);
67+
lockScreenDeviceIconManager.retrieveIcon(ICON_URL, listener);
68+
verify(listener, times(1)).onImageRetrieved((Bitmap) any());
8069
}
8170

82-
public void testUpdateCacheImageShouldReturnFalseWhenSharedPreferenceReturnsAnUpdatedIcon() {
83-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
84-
final Context context = Mockito.mock(Context.class);
85-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
86-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(15));
87-
88-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
89-
boolean imageUpToDate = lockScreenDeviceIconManager.isIconCachedAndValid(ICON_URL);
90-
assertTrue(imageUpToDate);
91-
}
9271

93-
public void testSaveFileToCacheShouldReturnBeforeWritingSharedPrefsIfSavingToCacheFails() {
72+
public void testRetrieveIconShouldCallOnImageOnImageRetrievedWithIconWhenCachedIconExpired() {
9473
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
95-
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
9674
final Context context = Mockito.mock(Context.class);
97-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
98-
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
99-
100-
Bitmap deviceLogo = null;
101-
try {
102-
deviceLogo = AndroidTools.downloadImage(ICON_URL);
103-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
104-
lockScreenDeviceIconManager.saveFileToCache(deviceLogo, ICON_URL);
105-
verify(sharedPrefs, times(0)).edit();
106-
verify(sharedPrefsEditor, times(0)).putString(anyString(), anyString());
107-
} catch (IOException e) {
108-
e.printStackTrace();
109-
}
110-
}
75+
final LockScreenDeviceIconManager.OnIconRetrievedListener listener = Mockito.mock(LockScreenDeviceIconManager.OnIconRetrievedListener.class);
11176

112-
public void testSaveFileToCacheShouldWriteToSharedPrefsIfSaveIconIsSuccessful() {
113-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
114-
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
115-
final Context context = Mockito.mock(Context.class);
11677
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
117-
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
118-
try {
119-
tempFolder.create();
120-
Mockito.when(context.getCacheDir()).thenReturn(tempFolder.newFolder());
121-
} catch (IOException e) {
122-
e.printStackTrace();
123-
}
124-
125-
Bitmap deviceLogo = null;
126-
try {
127-
deviceLogo = AndroidTools.downloadImage(ICON_URL);
128-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
129-
lockScreenDeviceIconManager.saveFileToCache(deviceLogo, ICON_URL);
130-
verify(sharedPrefs, times(1)).edit();
131-
verify(sharedPrefsEditor, times(1)).putString(anyString(), anyString());
132-
} catch (IOException e) {
133-
e.printStackTrace();
134-
}
135-
}
136-
137-
public void testGetFileFromCacheShouldReturnNullIfFailedToGetSystemPref() {
138-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
139-
final Context context = Mockito.mock(Context.class);
140-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
141-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(null);
78+
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(31));
14279

14380
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
144-
Bitmap cachedIcon = lockScreenDeviceIconManager.getFileFromCache(ICON_URL);
145-
assertNull(cachedIcon);
81+
lockScreenDeviceIconManager.retrieveIcon(ICON_URL, listener);
82+
verify(listener, times(1)).onImageRetrieved((Bitmap) any());
14683
}
14784

148-
public void testGetFileFromCacheShouldReturnNullIfInvalidDataFromSharedPref() {
85+
public void testRetrieveIconShouldCallOnImageRetrievedWithIconWhenCachedIconIsUpToDate() {
14986
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
150-
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
15187
final Context context = Mockito.mock(Context.class);
152-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
153-
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
154-
Mockito.when(sharedPrefsEditor.remove(anyString())).thenReturn(sharedPrefsEditor);
155-
Mockito.when(sharedPrefsEditor.commit()).thenReturn(true);
156-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn("");
157-
158-
159-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
160-
Bitmap cachedIcon = lockScreenDeviceIconManager.getFileFromCache(ICON_URL);
161-
assertNull(cachedIcon);
162-
}
163-
164-
public void testGetFileFromCacheShouldReturnNullIfFailedToFindIcon() {
165-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
16688
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
167-
final Context context = Mockito.mock(Context.class);
168-
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
169-
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
170-
Mockito.when(sharedPrefsEditor.remove(anyString())).thenReturn(sharedPrefsEditor);
171-
Mockito.when(sharedPrefsEditor.commit()).thenReturn(true);
172-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(15));
173-
174-
try {
175-
tempFolder.create();
176-
Mockito.when(context.getCacheDir()).thenReturn(tempFolder.newFolder());
177-
} catch (IOException e) {
178-
e.printStackTrace();
179-
}
180-
89+
final LockScreenDeviceIconManager.OnIconRetrievedListener listener = Mockito.mock(LockScreenDeviceIconManager.OnIconRetrievedListener.class);
18190

182-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
183-
Bitmap cachedIcon = lockScreenDeviceIconManager.getFileFromCache(ICON_URL);
184-
assertNull(cachedIcon);
185-
}
186-
187-
public void testGetFileFromCacheShouldReturnBitmapIfIconFoundInCache() {
188-
final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
189-
final SharedPreferences.Editor sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor.class);
190-
final Context context = Mockito.mock(Context.class);
19191
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
92+
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(15));
19293
Mockito.when(sharedPrefs.edit()).thenReturn(sharedPrefsEditor);
19394
Mockito.when(sharedPrefsEditor.remove(anyString())).thenReturn(sharedPrefsEditor);
194-
Mockito.when(sharedPrefsEditor.commit()).thenReturn(true);
195-
Bitmap deviceLogo = null;
19695

19796
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
198-
199-
try {
200-
tempFolder.create();
201-
File newFolder = tempFolder.newFolder();
202-
Mockito.when(context.getCacheDir()).thenReturn(newFolder);
203-
deviceLogo = AndroidTools.downloadImage(ICON_URL);
204-
Mockito.when(sharedPrefs.getString(anyString(), (String) isNull())).thenReturn(daysToMillisecondsAsString(15));
205-
} catch (IOException e) {
206-
e.printStackTrace();
207-
}
208-
209-
lockScreenDeviceIconManager = new LockScreenDeviceIconManager(context);
210-
lockScreenDeviceIconManager.saveFileToCache(deviceLogo, ICON_URL);
211-
Bitmap cachedIcon = lockScreenDeviceIconManager.getFileFromCache(ICON_URL);
212-
assertNotNull(cachedIcon);
97+
lockScreenDeviceIconManager.retrieveIcon(ICON_URL, listener);
98+
verify(listener, times(1)).onImageRetrieved((Bitmap) any());
21399
}
214-
100+
215101
private String daysToMillisecondsAsString(int days) {
216102
long milliSeconds = (long) days * 24 * 60 * 60 * 1000;
217103
long previousDay = System.currentTimeMillis() - milliSeconds;

android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenDeviceIconManager.java

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import android.graphics.Bitmap;
66
import android.graphics.BitmapFactory;
77

8+
import com.smartdevicelink.util.AndroidTools;
89
import com.smartdevicelink.util.DebugTool;
910

1011
import java.io.ByteArrayOutputStream;
1112
import java.io.File;
1213
import java.io.FileOutputStream;
14+
import java.io.IOException;
1315
import java.math.BigInteger;
1416
import java.security.MessageDigest;
1517
import java.security.NoSuchAlgorithmException;
@@ -18,15 +20,45 @@ class LockScreenDeviceIconManager {
1820

1921
private Context context;
2022
private static final String SDL_DEVICE_STATUS_SHARED_PREFS = "sdl.lockScreenIcon";
21-
private static final String STORED_ICON_PATH = "sdl/lock_screen_icon/";
23+
private static final String STORED_ICON_DIRECTORY_PATH = "sdl/lock_screen_icon/";
24+
25+
interface OnIconRetrievedListener {
26+
void onImageRetrieved(Bitmap icon);
27+
void onError(String info);
28+
}
2229

2330
LockScreenDeviceIconManager(Context context) {
2431
this.context = context;
25-
File lockScreenDirectory = new File(context.getCacheDir(), STORED_ICON_PATH);
32+
File lockScreenDirectory = new File(context.getCacheDir(), STORED_ICON_DIRECTORY_PATH);
2633
lockScreenDirectory.mkdirs();
2734
}
2835

29-
boolean isIconCachedAndValid(String iconUrl) {
36+
void retrieveIcon(String iconURL, OnIconRetrievedListener iconRetrievedListener) {
37+
Bitmap icon = null;
38+
try {
39+
if (isIconCachedAndValid(iconURL)) {
40+
DebugTool.logInfo("Icon Is Up To Date");
41+
icon = getFileFromCache(iconURL);
42+
if (icon == null) {
43+
DebugTool.logInfo("Icon from cache was null, attempting to re-download");
44+
icon = AndroidTools.downloadImage(iconURL);
45+
saveFileToCache(icon, iconURL);
46+
}
47+
iconRetrievedListener.onImageRetrieved(icon);
48+
} else {
49+
DebugTool.logInfo("Lock Screen Icon Update Needed");
50+
icon = AndroidTools.downloadImage(iconURL);
51+
saveFileToCache(icon, iconURL);
52+
iconRetrievedListener.onImageRetrieved(icon);
53+
}
54+
} catch (IOException e) {
55+
iconRetrievedListener.onError("device Icon Error Downloading, Will attempt to grab cached Icon even if expired: \n" + e.toString());
56+
icon = getFileFromCache(iconURL);
57+
iconRetrievedListener.onImageRetrieved(icon);
58+
}
59+
}
60+
61+
private boolean isIconCachedAndValid(String iconUrl) {
3062
String iconHash = getMD5HashFromIconUrl(iconUrl);
3163
SharedPreferences sharedPref = this.context.getSharedPreferences(SDL_DEVICE_STATUS_SHARED_PREFS, Context.MODE_PRIVATE);
3264
String iconLastUpdatedTime = sharedPref.getString(iconHash, null);
@@ -51,9 +83,9 @@ boolean isIconCachedAndValid(String iconUrl) {
5183
}
5284
}
5385

54-
void saveFileToCache(Bitmap icon, String iconUrl) {
86+
private void saveFileToCache(Bitmap icon, String iconUrl) {
5587
String iconHash = getMD5HashFromIconUrl(iconUrl);
56-
File f = new File(this.context.getCacheDir() + "/" + STORED_ICON_PATH, iconHash);
88+
File f = new File(this.context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH, iconHash);
5789
ByteArrayOutputStream bos = new ByteArrayOutputStream();
5890
icon.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
5991
byte[] bitmapData = bos.toByteArray();
@@ -73,13 +105,13 @@ void saveFileToCache(Bitmap icon, String iconUrl) {
73105
writeDeviceIconParametersToSharedPreferences(iconHash);
74106
}
75107

76-
Bitmap getFileFromCache(String iconUrl) {
108+
private Bitmap getFileFromCache(String iconUrl) {
77109
String iconHash = getMD5HashFromIconUrl(iconUrl);
78110
SharedPreferences sharedPref = this.context.getSharedPreferences(SDL_DEVICE_STATUS_SHARED_PREFS, Context.MODE_PRIVATE);
79111
String iconLastUpdatedTime = sharedPref.getString(iconHash, null);
80112

81113
if (iconLastUpdatedTime != null) {
82-
Bitmap cachedIcon = BitmapFactory.decodeFile(this.context.getCacheDir() + "/" + STORED_ICON_PATH + "/" + iconHash);
114+
Bitmap cachedIcon = BitmapFactory.decodeFile(this.context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH + "/" + iconHash);
83115
if(cachedIcon == null) {
84116
DebugTool.logError("Failed to get Bitmap from decoding file cache");
85117
clearIconDirectory();
@@ -101,7 +133,7 @@ private void writeDeviceIconParametersToSharedPreferences(String iconHash) {
101133
editor.commit();
102134
}
103135

104-
String getMD5HashFromIconUrl(String iconUrl) {
136+
private String getMD5HashFromIconUrl(String iconUrl) {
105137
String iconHash = null;
106138
try {
107139
MessageDigest md = MessageDigest.getInstance("MD5");
@@ -120,7 +152,7 @@ String getMD5HashFromIconUrl(String iconUrl) {
120152
}
121153

122154
private void clearIconDirectory() {
123-
File iconDir = new File(context.getCacheDir() + "/" + STORED_ICON_PATH);
155+
File iconDir = new File(context.getCacheDir() + "/" + STORED_ICON_DIRECTORY_PATH);
124156
if (iconDir.listFiles() != null) {
125157
for (File child : iconDir.listFiles()) {
126158
child.delete();

android/sdl_android/src/main/java/com/smartdevicelink/managers/lockscreen/LockScreenManager.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -379,23 +379,17 @@ private void downloadDeviceIcon(final String url){
379379
new Thread(new Runnable(){
380380
@Override
381381
public void run(){
382-
try{
383-
if(mLockScreenDeviceIconManager.isIconCachedAndValid(url)) {
384-
DebugTool.logInfo("Image Is Up To Date");
385-
deviceLogo = mLockScreenDeviceIconManager.getFileFromCache(url);
386-
if (deviceLogo == null) {
387-
deviceLogo = AndroidTools.downloadImage(url);
388-
mLockScreenDeviceIconManager.saveFileToCache(deviceLogo, url);
389-
}
390-
} else {
391-
DebugTool.logInfo("Lock Screen Icon Update Needed");
392-
deviceLogo = AndroidTools.downloadImage(url);
393-
mLockScreenDeviceIconManager.saveFileToCache(deviceLogo, url);
382+
mLockScreenDeviceIconManager.retrieveIcon(url, new LockScreenDeviceIconManager.OnIconRetrievedListener() {
383+
@Override
384+
public void onImageRetrieved(Bitmap icon) {
385+
deviceLogo = icon;
394386
}
395-
} catch(IOException e){
396-
Log.e(TAG, "device Icon Error Downloading, Will attempt to grab cached Icon even if expired: \n" + e.toString());
397-
deviceLogo = mLockScreenDeviceIconManager.getFileFromCache(url);
398-
}
387+
388+
@Override
389+
public void onError(String info) {
390+
DebugTool.logError(info);
391+
}
392+
});
399393
if(deviceLogo != null) {
400394
Intent intent = new Intent(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_DOWNLOADED);
401395
intent.putExtra(SDLLockScreenActivity.LOCKSCREEN_DEVICE_LOGO_EXTRA, deviceLogoEnabled);

0 commit comments

Comments
 (0)