Skip to content

Commit 5a52790

Browse files
authored
Merge pull request #24 from Jjastiny/androidOreoSupport
Android oreo support
2 parents 29ae565 + 4407784 commit 5a52790

File tree

6 files changed

+145
-40
lines changed

6 files changed

+145
-40
lines changed

.gitignore

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Built application files
2+
*.apk
3+
*.ap_
4+
5+
# Files for the ART/Dalvik VM
6+
*.dex
7+
8+
# Java class files
9+
*.class
10+
11+
# Generated files
12+
bin/
13+
gen/
14+
out/
15+
16+
# Gradle files
17+
.gradle/
18+
build/
19+
20+
# Local configuration file (sdk path, etc)
21+
local.properties
22+
23+
# Proguard folder generated by Eclipse
24+
proguard/
25+
26+
# Log Files
27+
*.log
28+
29+
# Android Studio Navigation editor temp files
30+
.navigation/
31+
32+
# Android Studio captures folder
33+
captures/
34+
35+
# IntelliJ
36+
*.iml
37+
.idea/workspace.xml
38+
.idea/tasks.xml
39+
.idea/gradle.xml
40+
.idea/dictionaries
41+
.idea/libraries
42+
.idea/*
43+
44+
# Keystore files
45+
# Uncomment the following line if you do not want to check your keystore files in.
46+
#*.jks
47+
48+
# External native build folder generated in Android Studio 2.2 and later
49+
.externalNativeBuild
50+
51+
# Google Services (e.g. APIs or Firebase)
52+
google-services.json
53+
54+
# Freeline
55+
freeline.py
56+
freeline/
57+
freeline_project_description.json

app/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
apply plugin: 'com.android.application'
22

33
android {
4-
compileSdkVersion 23
4+
compileSdkVersion 26
55
buildToolsVersion '26.0.2'
66

77
defaultConfig {
88
applicationId "iterable.com.androidsdk"
99
minSdkVersion 15
10-
targetSdkVersion 23
10+
targetSdkVersion 26
1111
versionCode 1
1212
versionName "1.0"
1313
}
@@ -22,7 +22,7 @@ android {
2222
dependencies {
2323
compile fileTree(include: ['*.jar'], dir: 'libs')
2424
testCompile 'junit:junit:4.12'
25-
compile 'com.android.support:appcompat-v7:23.2.1'
26-
compile 'com.android.support:design:23.2.1'
25+
compile 'com.android.support:appcompat-v7:26.0.2'
26+
compile 'com.android.support:design:26.0.2'
2727
compile project(':iterableapi')
2828
}

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
buildscript {
33
repositories {
44
jcenter()
5+
google()
56
}
67
dependencies {
78
classpath 'com.android.tools.build:gradle:3.0.0'
@@ -16,6 +17,7 @@ buildscript {
1617
allprojects {
1718
repositories {
1819
jcenter()
20+
google()
1921
}
2022
}
2123

iterableapi/build.gradle

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
apply plugin: 'com.android.library'
22

33
android {
4-
compileSdkVersion 23
4+
compileSdkVersion 26
55
buildToolsVersion '26.0.2'
66

77
defaultConfig {
88
minSdkVersion 15
9-
targetSdkVersion 23
9+
targetSdkVersion 26
1010
versionCode 1
1111
versionName "1.0"
1212
}
@@ -21,10 +21,10 @@ android {
2121
dependencies {
2222
compile fileTree(dir: 'libs', include: ['*.jar'])
2323
testCompile 'junit:junit:4.12'
24-
compile 'com.android.support:appcompat-v7:23.2.1'
25-
compile 'com.google.android.gms:play-services-gcm:9.0.2'
26-
compile 'com.google.firebase:firebase-messaging:9.0.2'
27-
compile 'com.android.support:support-annotations:23.2.1'
24+
compile 'com.android.support:appcompat-v7:26.0.2'
25+
compile 'com.google.android.gms:play-services-gcm:11.8.0'
26+
compile 'com.google.firebase:firebase-messaging:11.8.0'
27+
compile 'com.android.support:support-annotations:26.0.2'
2828
compile 'com.squareup.picasso:picasso:2.5.2'
2929
}
3030

iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableNotificationTest.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
package com.iterable.iterableapi;
22

3-
import android.annotation.TargetApi;
43
import android.app.Application;
54
import android.app.NotificationManager;
6-
import android.app.Service;
75
import android.content.Context;
8-
import android.os.AsyncTask;
96
import android.os.Build;
107
import android.os.Bundle;
118
import android.test.ApplicationTestCase;
129

13-
import java.util.concurrent.CountDownLatch;
14-
import java.util.concurrent.TimeUnit;
15-
1610
/**
1711
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
1812
*/
1913
public class IterableNotificationTest extends ApplicationTestCase<Application> {
2014
public IterableNotificationTest() {
2115
super(Application.class);
2216
}
17+
2318
Context appContext;
2419
NotificationManager mNotificationManager;
2520

@@ -63,9 +58,14 @@ public void testNotificationText() throws Exception {
6358
notif.putString(IterableConstants.ITERABLE_DATA_BODY, body);
6459
notif.putString(IterableConstants.ITERABLE_DATA_SOUND, sound);
6560

61+
getContext().getApplicationInfo().icon = android.R.drawable.sym_def_app_icon;
62+
6663
IterableNotification iterableNotification = IterableNotification.createNotification(getContext(), notif, Application.class);
6764
IterableNotification.postNotificationOnDevice(appContext, iterableNotification);
6865
assertEquals("IterableAPI", iterableNotification.mContentTitle);
66+
// It looks like mNotificationManager.notify(iterableNotification.requestCode, iterableNotification.build());
67+
// is the culprit here for the flaky tests. This thread is spun up by the android system. Unless we do dependency injection and mock the notificationManager, it'll be hard to make this unflake.
68+
Thread.sleep(100);
6969
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
7070
Bundle notificationExtras = mNotificationManager.getActiveNotifications()[0].getNotification().extras;
7171
assertEquals("IterableAPI", notificationExtras.get("android.title"));
@@ -76,9 +76,13 @@ public void testNotificationText() throws Exception {
7676
public void testMessage() throws Exception {
7777
Bundle notif1 = new Bundle();
7878
notif1.putString(IterableConstants.ITERABLE_DATA_KEY, itbl1);
79+
getContext().getApplicationInfo().icon = android.R.drawable.sym_def_app_icon;
7980

8081
IterableNotification iterableNotification = IterableNotification.createNotification(getContext(), notif1, Application.class);
8182
IterableNotification.postNotificationOnDevice(appContext, iterableNotification);
83+
// It looks like mNotificationManager.notify(iterableNotification.requestCode, iterableNotification.build());
84+
// is the culprit here for the flaky tests. This thread is spun up by the android system. Unless we do dependency injection and mock the notificationManager, it'll be hard to make this unflake.
85+
Thread.sleep(100);
8286
assertFalse(iterableNotification.iterableNotificationData.getIsGhostPush());
8387
assertEquals("11111111111111111111111111111111", iterableNotification.iterableNotificationData.getMessageId());
8488
assertEquals("11111111111111111111111111111111".hashCode(), iterableNotification.requestCode);
@@ -90,9 +94,13 @@ public void testMessage() throws Exception {
9094

9195
Bundle notif2 = new Bundle();
9296
notif2.putString(IterableConstants.ITERABLE_DATA_KEY, itbl2);
97+
getContext().getApplicationInfo().icon = android.R.drawable.sym_def_app_icon;
9398

9499
IterableNotification iterableNotification2 = IterableNotification.createNotification(getContext(), notif2, Application.class);
95100
IterableNotification.postNotificationOnDevice(appContext, iterableNotification2);
101+
// It looks like mNotificationManager.notify(iterableNotification.requestCode, iterableNotification.build());
102+
// is the culprit here for the flaky tests. This thread is spun up by the android system. Unless we do dependency injection and mock the notificationManager, it'll be hard to make this unflake.
103+
Thread.sleep(100);
96104
assertFalse(iterableNotification2.iterableNotificationData.getIsGhostPush());
97105
assertEquals("22222222222222222222222222222222", iterableNotification2.iterableNotificationData.getMessageId());
98106
assertEquals("22222222222222222222222222222222".hashCode(), iterableNotification2.requestCode);

iterableapi/src/main/java/com/iterable/iterableapi/IterableNotification.java

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.iterable.iterableapi;
22

33
import android.app.Notification;
4+
import android.app.NotificationChannel;
45
import android.app.NotificationManager;
56
import android.app.PendingIntent;
67
import android.content.Context;
@@ -20,18 +21,17 @@
2021
import org.json.JSONObject;
2122

2223
/**
23-
*
2424
* Created by David Truong [email protected]
2525
*/
2626
public class IterableNotification extends NotificationCompat.Builder {
2727
static final String TAG = "IterableNotification";
2828
private boolean isGhostPush;
29-
private String imageUrl;
29+
private String imageUrl;
3030
int requestCode;
3131
IterableNotificationData iterableNotificationData;
3232

33-
protected IterableNotification(Context context) {
34-
super(context);
33+
protected IterableNotification(Context context, String channelId) {
34+
super(context, channelId);
3535
}
3636

3737
/**
@@ -67,21 +67,26 @@ public void run() {
6767

6868
/**
6969
* Creates and returns an instance of IterableNotification.
70+
*
7071
* @param context
7172
* @param extras
7273
* @param classToOpen
7374
* @return Returns null if the intent comes from an Iterable ghostPush
7475
*/
7576
public static IterableNotification createNotification(Context context, Bundle extras, Class classToOpen) {
7677
int stringId = context.getApplicationInfo().labelRes;
77-
String applicationName = context.getString(stringId);
78+
String applicationName = context.getString(stringId);
7879
String notificationBody = null;
7980
String soundName = null;
8081
String messageId = null;
8182
String pushImage = null;
83+
//TODO: When backend supports channels, these strings needs to change (channelName, channelId, channelDescription).
84+
String channelName = "iterable channel";
85+
String channelId = context.getPackageName();
86+
String channelDescription = "";
8287

83-
IterableNotification notificationBuilder = new IterableNotification(context);
84-
88+
registerChannelIfEmpty(context, channelId, channelName, channelDescription);
89+
IterableNotification notificationBuilder = new IterableNotification(context, context.getPackageName());
8590
if (extras.containsKey(IterableConstants.ITERABLE_DATA_KEY)) {
8691
applicationName = extras.getString(IterableConstants.ITERABLE_DATA_TITLE, applicationName);
8792
notificationBody = extras.getString(IterableConstants.ITERABLE_DATA_BODY);
@@ -110,20 +115,20 @@ public static IterableNotification createNotification(Context context, Bundle ex
110115
notifPermissions.defaults |= Notification.DEFAULT_LIGHTS;
111116

112117
notificationBuilder
113-
.setSmallIcon(getIconId(context))
114-
.setTicker(applicationName).setWhen(0)
115-
.setAutoCancel(true)
116-
.setContentTitle(applicationName)
117-
.setPriority(Notification.PRIORITY_HIGH)
118-
.setContentText(notificationBody);
118+
.setSmallIcon(getIconId(context))
119+
.setTicker(applicationName).setWhen(0)
120+
.setAutoCancel(true)
121+
.setContentTitle(applicationName)
122+
.setPriority(Notification.PRIORITY_HIGH)
123+
.setContentText(notificationBody);
119124

120125
if (pushImage != null) {
121126
notificationBuilder.imageUrl = pushImage;
122127
notificationBuilder.setContentText(notificationBody)
123-
.setStyle(new NotificationCompat.BigPictureStyle()
124-
.setBigContentTitle(applicationName)
125-
.setSummaryText(notificationBody)
126-
);
128+
.setStyle(new NotificationCompat.BigPictureStyle()
129+
.setBigContentTitle(applicationName)
130+
.setSummaryText(notificationBody)
131+
);
127132
} else {
128133
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(notificationBody));
129134
}
@@ -133,7 +138,7 @@ public static IterableNotification createNotification(Context context, Bundle ex
133138
String[] soundFile = soundName.split("\\.");
134139
soundName = soundFile[0];
135140

136-
if (!soundName.equalsIgnoreCase(IterableConstants.DEFAULT_SOUND)){
141+
if (!soundName.equalsIgnoreCase(IterableConstants.DEFAULT_SOUND)) {
137142
int soundID = context.getResources().getIdentifier(soundName, IterableConstants.SOUND_FOLDER_IDENTIFIER, context.getPackageName());
138143
Uri soundUri = Uri.parse(IterableConstants.ANDROID_RESOURCE_PATH + context.getPackageName() + "/" + soundID);
139144
notificationBuilder.setSound(soundUri);
@@ -175,6 +180,7 @@ public static IterableNotification createNotification(Context context, Bundle ex
175180
/**
176181
* Posts the notification on device.
177182
* Only sets the notification if it is not a ghostPush/null iterableNotification.
183+
*
178184
* @param context
179185
* @param iterableNotification Function assumes that the iterableNotification is a ghostPush
180186
* if the IterableNotification passed in is null.
@@ -187,8 +193,40 @@ public static void postNotificationOnDevice(Context context, IterableNotificatio
187193
}
188194
}
189195

196+
/**
197+
* Creates the notification channel on device.
198+
* Only creates the notification channel if application does not have notification channel created.
199+
*
200+
* @param context
201+
* @param channelId Determines the channel Id. This distinguishes if the app has different channel or not.
202+
* @param channelName Sets the channel name that is shown to the user.
203+
* @param channelDescription Sets the channel description that is shown to the user.
204+
*/
205+
private static void registerChannelIfEmpty(Context context, String channelId, String channelName, String channelDescription) {
206+
NotificationManager mNotificationManager = (NotificationManager)
207+
context.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
208+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O
209+
&& mNotificationManager != null
210+
&& mNotificationManager.getNotificationChannel(channelId) == null) {
211+
IterableLogger.d(TAG, "Creating notification: channelId = " + channelId + " channelName = "
212+
+ channelName + " channelDescription = " + channelDescription);
213+
mNotificationManager.createNotificationChannel(createNotificationChannel(channelId, channelName, channelDescription));
214+
}
215+
}
216+
217+
private static NotificationChannel createNotificationChannel(String channelId, String channelName, String channelDescription) {
218+
NotificationChannel notificationChannel = null;
219+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
220+
notificationChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
221+
notificationChannel.setDescription(channelDescription);
222+
notificationChannel.enableLights(true);
223+
}
224+
return notificationChannel;
225+
}
226+
190227
/**
191228
* Returns the iconId from potential resource locations
229+
*
192230
* @param context
193231
* @return
194232
*/
@@ -200,7 +238,7 @@ private static int getIconId(Context context) {
200238
try {
201239
ApplicationInfo info = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
202240
iconId = info.metaData.getInt(IterableConstants.NOTIFICATION_ICON_NAME, 0);
203-
IterableLogger.d(TAG, "iconID: "+ info.metaData.get(IterableConstants.NOTIFICATION_ICON_NAME));
241+
IterableLogger.d(TAG, "iconID: " + info.metaData.get(IterableConstants.NOTIFICATION_ICON_NAME));
204242
} catch (PackageManager.NameNotFoundException e) {
205243
e.printStackTrace();
206244
}
@@ -209,18 +247,17 @@ private static int getIconId(Context context) {
209247
//Get the iconId set in code
210248
if (iconId == 0) {
211249
iconId = context.getResources().getIdentifier(
212-
IterableApi.getNotificationIcon(context),
213-
IterableConstants.ICON_FOLDER_IDENTIFIER,
214-
context.getPackageName());
250+
IterableApi.getNotificationIcon(context),
251+
IterableConstants.ICON_FOLDER_IDENTIFIER,
252+
context.getPackageName());
215253
}
216254

217255
//Get id from the default app settings
218256
if (iconId == 0) {
219257
if (context.getApplicationInfo().icon != 0) {
220258
IterableLogger.d(TAG, "No Notification Icon defined - defaulting to app icon");
221259
iconId = context.getApplicationInfo().icon;
222-
}
223-
else {
260+
} else {
224261
IterableLogger.w(TAG, "No Notification Icon defined - push notifications will not be displayed");
225262
}
226263
}
@@ -230,6 +267,7 @@ private static int getIconId(Context context) {
230267

231268
/**
232269
* Returns if the given notification is a ghost/silent push notification
270+
*
233271
* @param extras
234272
* @return
235273
*/

0 commit comments

Comments
 (0)