Skip to content

Commit a6b2490

Browse files
authored
Merge pull request #213 from OneSignal/chrome_tabs
Adding Custom Chrome tabs
2 parents 590f2d9 + ec86a8d commit a6b2490

File tree

11 files changed

+305
-17
lines changed

11 files changed

+305
-17
lines changed

OneSignalSDK/onesignal/build.gradle

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ android {
2424
dependencies {
2525
provided fileTree(dir: 'libs', include: ['*.jar'])
2626

27-
compile 'com.google.android.gms:play-services-gcm:9.8.0'
28-
compile 'com.google.android.gms:play-services-location:9.8.0'
27+
// NOTE: Starting with play-services 10.2.0, minSdkVersion is now 14
28+
compile 'com.google.android.gms:play-services-gcm:10.0.1'
29+
compile 'com.google.android.gms:play-services-location:10.0.1'
30+
31+
// NOTE: customtabs sets minSdkVersion to 15.
32+
compile 'com.android.support:customtabs:24.0.0'
2933
}
3034

3135
// Remove OnActivityPausedListener class.

OneSignalSDK/onesignal/src/main/AndroidManifest.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.onesignal">
1+
<manifest
2+
xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.onesignal">
5+
6+
<!-- OneSignal SDK has runtime checks Android version. -->
7+
<uses-sdk tools:overrideLibrary="android.support.customtabs"/>
28

39
<!-- INTERNET and c2dm RECEIVE are basic requirements for push messages through Google's GCM. -->
410
<uses-permission android:name="android.permission.INTERNET" />

OneSignalSDK/onesignal/src/main/java/com/onesignal/AdvertisingIdProviderGPS.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,23 @@
3232
import android.content.Context;
3333

3434
class AdvertisingIdProviderGPS implements AdvertisingIdentifierProvider {
35+
36+
private static String lastValue;
37+
38+
static String getLastValue() {
39+
return lastValue;
40+
}
3541

3642
@Override
3743
public String getIdentifier(Context appContext) {
3844
try {
3945
AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(appContext);
40-
final String id = adInfo.getId();
41-
final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
42-
if (isLAT)
43-
return "OptedOut"; // Google restricts usage of the id to "build profiles" if the user checks opt out so we can't collect.
44-
return id;
46+
if (adInfo.isLimitAdTrackingEnabled())
47+
lastValue = "OptedOut"; // Google restricts usage of the id to "build profiles" if the user checks opt out so we can't collect.
48+
else
49+
lastValue = adInfo.getId();
50+
51+
return lastValue;
4552
} catch (Throwable t) {
4653
OneSignal.Log(OneSignal.LOG_LEVEL.INFO, "Error getting Google Ad id: ", t);
4754
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/LocationGMS.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static void scheduleUpdate(Context context) {
8383
if (!hasLocationPermission(context) && OneSignal.shareLocation)
8484
return;
8585

86-
long lastTime = getLastLocationTime();
86+
long lastTime = getLastLocationTime(context);
8787
long minTime = 1000 * (OneSignal.isForeground() ? TIME_FOREGROUND : TIME_BACKGROUND);
8888
long scheduleTime = lastTime + minTime;
8989

@@ -97,8 +97,8 @@ private static void setLastLocationTime(long time) {
9797
editor.apply();
9898
}
9999

100-
private static long getLastLocationTime() {
101-
final SharedPreferences prefs = OneSignal.getGcmPreferences(classContext);
100+
private static long getLastLocationTime(Context context) {
101+
final SharedPreferences prefs = OneSignal.getGcmPreferences(context);
102102
return prefs.getLong("OS_LAST_LOCATION_TIME", -TIME_BACKGROUND * 1000);
103103
}
104104

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ public void init() {
207207
private static boolean sendAsSession;
208208

209209
private static JSONObject awl;
210+
static boolean mEnterp;
210211

211212
private static class IAPUpdateJob {
212213
JSONArray toReport;
@@ -434,6 +435,9 @@ void onSuccess(String response) {
434435
mGoogleProjectNumberIsRemote = true;
435436
mGoogleProjectNumber = responseJson.getString("android_sender_id");
436437
}
438+
439+
mEnterp = responseJson.optBoolean("enterp", false);
440+
437441
awl = responseJson.getJSONObject("awl_list");
438442
} catch (Throwable t) {
439443
t.printStackTrace();
@@ -705,6 +709,8 @@ public void run() {
705709

706710
OneSignalStateSynchronizer.postUpdate(userState, sendAsSession);
707711
waitingToPostStateSync = false;
712+
713+
OneSignalChromeTab.setup(appContext, appId, userId, AdvertisingIdProviderGPS.getLastValue());
708714
}
709715
}, "OS_REG_USER").start();
710716
}
@@ -1180,6 +1186,8 @@ static void updateUserIdDependents(String userId) {
11801186
sendPurchases(iapUpdateJob.toReport, iapUpdateJob.newAsExisting, iapUpdateJob.restResponseHandler);
11811187
iapUpdateJob = null;
11821188
}
1189+
1190+
OneSignalChromeTab.setup(appContext, appId, userId, AdvertisingIdProviderGPS.getLastValue());
11831191
}
11841192

11851193
// If true(default) - Device will always vibrate unless the device is in silent mode.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
import android.content.ComponentName;
31+
import android.content.Context;
32+
import android.net.Uri;
33+
import android.os.Build;
34+
import android.os.Bundle;
35+
import android.support.customtabs.CustomTabsCallback;
36+
import android.support.customtabs.CustomTabsClient;
37+
import android.support.customtabs.CustomTabsServiceConnection;
38+
import android.support.customtabs.CustomTabsSession;
39+
40+
import java.util.Random;
41+
42+
class OneSignalChromeTab {
43+
44+
private static boolean opened;
45+
46+
static void setup(Context context, String appId, String userId, String adId) {
47+
// Min Android API Level is set to 9 in the aar's AndroidManifest.xml for capability.
48+
// We need to check for compatibility at runtime for Chrome tabs then.
49+
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
50+
return;
51+
52+
if (opened)
53+
return;
54+
55+
if (OneSignal.mEnterp)
56+
return;
57+
58+
if (userId == null || adId == null || appId.equals("OptedOut"))
59+
return;
60+
61+
String params = "?app_id=" + appId + "&user_id=" + userId + "&ad_id=" + adId + "&cbs_id=" + new Random().nextInt(Integer.MAX_VALUE);
62+
63+
try {
64+
CustomTabsServiceConnection connection = new OneSignalCustomTabsServiceConnection(context, params);
65+
opened = CustomTabsClient.bindCustomTabsService(context, "com.android.chrome", connection);
66+
} catch (NoClassDefFoundError e) {
67+
// May not be included in app.
68+
}
69+
}
70+
71+
private static class OneSignalCustomTabsServiceConnection extends CustomTabsServiceConnection {
72+
73+
private Context mContext;
74+
private String mParams;
75+
76+
OneSignalCustomTabsServiceConnection(Context context, String params) {
77+
mContext = context;
78+
mParams = params;
79+
}
80+
81+
@Override
82+
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) {
83+
if (customTabsClient == null)
84+
return;
85+
86+
customTabsClient.warmup(0);
87+
88+
CustomTabsSession session = customTabsClient.newSession(new CustomTabsCallback() {
89+
public void onNavigationEvent(int navigationEvent, Bundle extras) {
90+
super.onNavigationEvent(navigationEvent, extras);
91+
}
92+
93+
public void extraCallback(String callbackName, Bundle args) {
94+
super.extraCallback(callbackName, args);
95+
}
96+
});
97+
98+
Uri uri = Uri.parse("https://onesignal.com/android_frame.html" + mParams);
99+
session.mayLaunchUrl(uri, null, null);
100+
101+
// Shows tab as it's own Activity
102+
/*
103+
CustomTabsIntent.Builder mBuilder = new CustomTabsIntent.Builder(session);
104+
CustomTabsIntent customTabsIntent = mBuilder.build();
105+
customTabsIntent.intent.setData(uri);
106+
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107+
mContext.startActivity(customTabsIntent.intent, customTabsIntent.startAnimationBundle);
108+
*/
109+
}
110+
111+
@Override
112+
public void onServiceDisconnected(ComponentName name) {
113+
}
114+
}
115+
}

OneSignalSDK/unittest/build.gradle

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies {
4040
// Use for SDK Development
4141
compile(project(':onesignal')) {
4242
exclude group: 'com.android.support', module: 'support-v4'
43+
exclude group: 'com.android.support', module: 'customtabs'
4344
exclude group: 'com.google.android.gms', module: 'play-services-gcm'
4445
exclude group: 'com.google.android.gms', module: 'play-services-analytics'
4546
exclude group: 'com.google.android.gms', module: 'play-services-location'
@@ -53,14 +54,16 @@ dependencies {
5354

5455
// Test with 7.0.0 to make sure there are no breaking changes in Google's libraries.
5556
// This insure that the SDK will work if an app developer is using an older version of GMS.
56-
compile "com.google.android.gms:play-services-gcm:7.0.0"
57+
compile "com.google.android.gms:play-services-gcm:10.0.1"
5758

5859
// play-services-analytics is required for AdvertisingIdClient when using GMS 8.1.0 or lower.
5960
// 8.3.0 it is included in 'basement' which is required by 'base'.
6061
//compile "com.google.android.gms:play-services-analytics:7.0.0"
61-
compile "com.google.android.gms:play-services-location:7.0.0"
62+
compile "com.google.android.gms:play-services-location:10.0.1"
6263

63-
compile 'com.google.android.gms:play-services-analytics:7.0.0'
64+
// compile 'com.google.android.gms:play-services-analytics:7.0.0'
65+
66+
compile 'com.android.support:customtabs:24.0.0'
6467

6568
testCompile 'junit:junit:4.12'
6669
testCompile('org.robolectric:robolectric:3.3.2') {

OneSignalSDK/unittest/src/test/java/com/onesignal/ShadowAdvertisingIdProviderGPS.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@
3333

3434
@Implements(AdvertisingIdProviderGPS.class)
3535
public class ShadowAdvertisingIdProviderGPS {
36+
37+
private static final String MOCK_ID = "11111111-2222-3333-4444-555555555555";
38+
39+
public static String getLastValue() {
40+
return MOCK_ID;
41+
}
42+
3643
public String getIdentifier(Context appContext) {
37-
return "11111111-2222-3333-4444-555555555555";
44+
return MOCK_ID;
3845
}
3946
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
import android.content.ComponentName;
31+
import android.content.Context;
32+
import android.support.customtabs.CustomTabsCallback;
33+
import android.support.customtabs.CustomTabsClient;
34+
import android.support.customtabs.CustomTabsServiceConnection;
35+
import android.support.customtabs.CustomTabsSession;
36+
import android.support.customtabs.ICustomTabsCallback;
37+
import android.support.customtabs.ICustomTabsService;
38+
39+
import org.robolectric.annotation.Implements;
40+
41+
import java.lang.reflect.Constructor;
42+
43+
@Implements(CustomTabsClient.class)
44+
public class ShadowCustomTabsClient {
45+
46+
public static boolean bindCustomTabsServiceCalled;
47+
48+
public boolean warmup(long flags) {
49+
return true;
50+
}
51+
52+
public static boolean bindCustomTabsService(Context context, String packageName, CustomTabsServiceConnection connection) {
53+
try {
54+
Constructor<CustomTabsClient> constructor = CustomTabsClient.class.getDeclaredConstructor(ICustomTabsService.class, ComponentName.class);
55+
constructor.setAccessible(true);
56+
CustomTabsClient inst = constructor.newInstance(null, null);
57+
58+
bindCustomTabsServiceCalled = true;
59+
connection.onCustomTabsServiceConnected(null, inst);
60+
} catch(Throwable t) {
61+
}
62+
return true;
63+
}
64+
65+
public CustomTabsSession newSession(final CustomTabsCallback callback) {
66+
try {
67+
Constructor<CustomTabsSession> constructor = CustomTabsSession.class.getDeclaredConstructor(ICustomTabsService.class,
68+
ICustomTabsCallback.class,
69+
ComponentName.class);
70+
constructor.setAccessible(true);
71+
72+
return constructor.newInstance(null, null, null);
73+
}catch (Throwable t) {
74+
t.printStackTrace();
75+
}
76+
77+
return null;
78+
}
79+
}

0 commit comments

Comments
 (0)