Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
skykelsey committed Jul 13, 2016
2 parents 25a47e9 + d7c0cd7 commit dda74f8
Show file tree
Hide file tree
Showing 36 changed files with 1,043 additions and 571 deletions.
4 changes: 2 additions & 2 deletions .idea/codeStyleSettings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 14 additions & 3 deletions .idea/runConfigurations/Apptentive_Tests.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# 2016-06-24 - 3.1.2
# 2016-07-13 - 3.2.0

#### Improvements

* Added a new "NPS" question type for surveys.

#### Bugs Fixed

* Fix Message Center composing bar exception thrown when the animation was in play after the fragment was detached
* Fixed Message Center composing bar exception thrown when the animation was in play after the fragment was detached.
* Fixed Message Center exception caused by requesting focus on a nulled EditText.
* Moved database calls off the UI thread.

# 2016-06-20 - 3.1.1

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use your app, to talk to them at the right time, and in the right way.

##### Version history is tracked [here](CHANGELOG.md)

##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|3.1.2|aar)
##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|3.2.0|aar)
#### Reporting Bugs

We encourage you to help us find and fix bugs. If you find a bug, please fill in the contributor agreement, then open a [github issue](https://github.com/apptentive/apptentive-android/issues?direction=desc&sort=created&state=open).
Expand Down
93 changes: 80 additions & 13 deletions apptentive/src/main/java/com/apptentive/android/sdk/Apptentive.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
package com.apptentive.android.sdk;

import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;

Expand Down Expand Up @@ -471,7 +473,7 @@ public static boolean isApptentivePushNotification(Intent intent) {
* Determines whether this Bundle came from an Apptentive push notification. This method is used with Urban Airship
* integrations.
*
* @param bundle The Extra data from an opened push notification.
* @param bundle The push payload bundle paseed to GCM onMessageReceived() callback
* @return True if the Intent contains Apptentive push information.
*/
public static boolean isApptentivePushNotification(Bundle bundle) {
Expand All @@ -481,6 +483,19 @@ public static boolean isApptentivePushNotification(Bundle bundle) {
return ApptentiveInternal.getApptentivePushNotificationData(bundle) != null;
}

/**
* Determines whether push payload data came from an Apptentive push notification.
*
* @param data The push payload data obtained through FCM RemoteMessage::getData() when using FCM
* @return True if the Intent contains Apptentive push information.
*/
public static boolean isApptentivePushNotification(Map<String, String> data) {
if (!ApptentiveInternal.isApptentiveRegistered()) {
return false;
}
return ApptentiveInternal.getApptentivePushNotificationData(data) != null;
}

/**
* <p>Saves Apptentive specific data from a push notification Intent. In your BroadcastReceiver, if the push notification
* came from Apptentive, it will have data that needs to be saved before you launch your Activity. You must call this
Expand Down Expand Up @@ -514,6 +529,7 @@ public static boolean setPendingPushNotification(Intent intent) {
* @param data A Bundle containing the GCM data object from the push notification.
* @return true if the push data came from Apptentive.
*/
@Deprecated
public static boolean setPendingPushNotification(Bundle data) {
if (!ApptentiveInternal.isApptentiveRegistered()) {
return false;
Expand All @@ -526,6 +542,56 @@ public static boolean setPendingPushNotification(Bundle data) {
return false;
}

/**
* Use this method in your push receiver to build a pending Intent when an Apptentive push notification
* is received. This pending Intent will be launched when the user taps on the push notification, and will
* allow Apptentive to open UIs such as Message Center. This will generally be used with direct Apptentive Push, as
* a replacement of {@link #setPendingPushNotification(Bundle)}. Calling this method for a push that did
* not come from Apptentive will return a null object.
*
* @param data A Bundle containing the Apptentive Push data. Normally bundle parameter passed into onMessageReceived()of gmc
* @return a valid pending intent to launch Message Center if the push data came from Apptentive, or null.
*/
public static PendingIntent buildPendingPushNotificationIntent(@NonNull Object data) {
if (!ApptentiveInternal.isApptentiveRegistered()) {
return null;
}

String apptentivePushData = null;
if (data instanceof Bundle) {
apptentivePushData = ApptentiveInternal.getApptentivePushNotificationData((Bundle) data);
} else if (data instanceof Map) {
apptentivePushData = ApptentiveInternal.getApptentivePushNotificationData((Map) data);
}
if (!TextUtils.isEmpty(apptentivePushData)) {
try {
JSONObject pushJson = new JSONObject(apptentivePushData);
ApptentiveInternal.PushAction action = ApptentiveInternal.PushAction.unknown;
if (pushJson.has(ApptentiveInternal.PUSH_ACTION)) {
action = ApptentiveInternal.PushAction.parse(pushJson.getString(ApptentiveInternal.PUSH_ACTION));
}
switch (action) {
case pmc: {
// Prefetch message when push for message center is received
MessageManager mgr = ApptentiveInternal.getInstance().getMessageManager();
if (mgr != null) {
mgr.startMessagePreFetchTask();
}
// Construct a pending intent to launch message center
return ApptentiveInternal.prepareMessageCenterPendingIntent(ApptentiveInternal.getInstance().getApplicationContext());
}
default:
ApptentiveLog.w("Unknown Apptentive push notification action: \"%s\"", action.name());
}
} catch (JSONException e) {
ApptentiveLog.e("Error parsing JSON from push notification.", e);
MetricModule.sendError(e, "Parsing Apptentive Push", apptentivePushData);
}
}

return null;
}

/**
* Launches Apptentive features based on a push notification Intent. Before you call this, you
* must call {@link #setPendingPushNotification(Intent)} or
Expand All @@ -538,6 +604,7 @@ public static boolean setPendingPushNotification(Bundle data) {
* @param context The context from which this method is called.
* @return True if a call to this method resulted in Apptentive displaying a View.
*/
@Deprecated
public static boolean handleOpenedPushNotification(Context context) {
if (!ApptentiveInternal.isApptentiveRegistered()) {
return false;
Expand Down Expand Up @@ -621,8 +688,8 @@ public static boolean showMessageCenter(Context context) {
* method is invoked. Additional invocations of this method with custom data will repeat this process.
*
* @param context The context from which to launch the Message Center. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Message Center will launch in a new task.
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Message Center will launch in a new task.
* @param customData A Map of String keys to Object values. Objects may be Strings, Numbers, or Booleans.
* If any message is sent by the Person, this data is sent with it, and then
* cleared. If no message is sent, this data is discarded.
Expand Down Expand Up @@ -659,7 +726,7 @@ public static boolean canShowMessageCenter() {
* won't get notification. Please use {@link #addUnreadMessagesListener(UnreadMessagesListener)} instead.
*
* @param listener An UnreadMessagesListener that you instantiate. Pass null to remove existing listener.
* Do not pass in an anonymous class, such as setUnreadMessagesListener(new UnreadMessagesListener() {...}).
* Do not pass in an anonymous class, such as setUnreadMessagesListener(new UnreadMessagesListener() {...}).
* Instead, create your listener as an instance variable and pass that in. This
* allows us to keep a weak reference to avoid memory leaks.
*/
Expand Down Expand Up @@ -857,9 +924,9 @@ public static void sendAttachmentFile(InputStream is, String mimeType) {
* can run, then the most appropriate interaction takes precedence. Only one interaction at most will run per
* invocation of this method.
*
* @param context The context from which to launch the Interaction. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* @param context The context from which to launch the Interaction. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* @param event A unique String representing the line this method is called on. For instance, you may want to have
* the ability to target interactions to run after the user uploads a file in your app. You may then
* call <strong><code>engage(context, "finished_upload");</code></strong>
Expand All @@ -876,8 +943,8 @@ public static synchronized boolean engage(Context context, String event) {
* invocation of this method.
*
* @param context The context from which to launch the Interaction. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* @param event A unique String representing the line this method is called on. For instance, you may want to have
* the ability to target interactions to run after the user uploads a file in your app. You may then
* call <strong><code>engage(context, "finished_upload");</code></strong>
Expand All @@ -895,9 +962,9 @@ public static synchronized boolean engage(Context context, String event, Map<Str
* can run, then the most appropriate interaction takes precedence. Only one interaction at most will run per
* invocation of this method.
*
* @param context The context from which to launch the Interaction. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* @param context The context from which to launch the Interaction. This should be an
* Activity, except in rare cases where you don't have access to one, in which
* case Apptentive Interactions will launch in a new task.
* @param event A unique String representing the line this method is called on. For instance, you may want to have
* the ability to target interactions to run after the user uploads a file in your app. You may then
* call <strong><code>engage(context, "finished_upload");</code></strong>
Expand Down Expand Up @@ -951,7 +1018,7 @@ public static synchronized boolean canShowInteraction(String event) {
* a weak reference to avoid memory leaks.
*
* @param listener The {@link com.apptentive.android.sdk.module.survey.OnSurveyFinishedListener} listener
* to call when the survey is finished.
* to call when the survey is finished.
*/
public static void setOnSurveyFinishedListener(OnSurveyFinishedListener listener) {
ApptentiveInternal internal = ApptentiveInternal.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
import com.apptentive.android.sdk.module.rating.impl.GooglePlayRatingProvider;
import com.apptentive.android.sdk.module.survey.OnSurveyFinishedListener;
import com.apptentive.android.sdk.storage.AppReleaseManager;
import com.apptentive.android.sdk.storage.ApptentiveDatabase;
import com.apptentive.android.sdk.storage.ApptentiveTaskManager;
import com.apptentive.android.sdk.storage.DeviceManager;
import com.apptentive.android.sdk.storage.PayloadSendWorker;
import com.apptentive.android.sdk.storage.PersonManager;
Expand Down Expand Up @@ -77,12 +77,15 @@ public class ApptentiveInternal {
InteractionManager interactionManager;
MessageManager messageManager;
PayloadSendWorker payloadWorker;
ApptentiveDatabase database;
ApptentiveTaskManager taskManager;
CodePointStore codePointStore;
ApptentiveActivityLifecycleCallbacks lifecycleCallbacks;

// These variables are initialized in Apptentive.register(), and so they are freely thereafter. If they are unexpectedly null, then if means the host app did not register Apptentive.
Context appContext;
Integer currentVersionCode;
String currentVersionName;

boolean appIsInForeground;
boolean isAppDebuggable;
SharedPreferences prefs;
Expand Down Expand Up @@ -167,13 +170,13 @@ public static ApptentiveInternal createInstance(Context context, final String ap
MessageManager msgManager = new MessageManager();
PayloadSendWorker payloadWorker = new PayloadSendWorker();
InteractionManager interactionMgr = new InteractionManager();
ApptentiveDatabase db = new ApptentiveDatabase(sApptentiveInternal.appContext);
ApptentiveTaskManager worker = new ApptentiveTaskManager(sApptentiveInternal.appContext);
CodePointStore store = new CodePointStore();

sApptentiveInternal.messageManager = msgManager;
sApptentiveInternal.payloadWorker = payloadWorker;
sApptentiveInternal.interactionManager = interactionMgr;
sApptentiveInternal.database = db;
sApptentiveInternal.taskManager = worker;
sApptentiveInternal.codePointStore = store;
sApptentiveInternal.cachedExecutor = Executors.newCachedThreadPool();
sApptentiveInternal.apiKey = Util.trim(apptentiveApiKey);
Expand Down Expand Up @@ -298,6 +301,14 @@ public Context getApplicationContext() {
return appContext;
}

public int getApplicationVersionCode() {
return currentVersionCode;
}

public String getApplicationVersionName() {
return currentVersionName;
}

public ApptentiveActivityLifecycleCallbacks getRegisteredLifecycleCallbacks() {
return lifecycleCallbacks;
}
Expand Down Expand Up @@ -328,8 +339,8 @@ public PayloadSendWorker getPayloadWorker() {
return payloadWorker;
}

public ApptentiveDatabase getApptentiveDatabase() {
return database;
public ApptentiveTaskManager getApptentiveTaskManager() {
return taskManager;
}

public CodePointStore getCodePointStore() {
Expand Down Expand Up @@ -563,8 +574,8 @@ public boolean init() {
// check if host app defines an apptentive theme override
int themeOverrideResId = appContext.getResources().getIdentifier("ApptentiveThemeOverride", "style", appPackageName);

Integer currentVersionCode = packageInfo.versionCode;
String currentVersionName = packageInfo.versionName;
currentVersionCode = packageInfo.versionCode;
currentVersionName = packageInfo.versionName;
VersionHistoryStore.VersionHistoryEntry lastVersionEntrySeen = VersionHistoryStore.getLastVersionSeen();
AppRelease appRelease = new AppRelease();
appRelease.setVersion(currentVersionName);
Expand Down Expand Up @@ -653,7 +664,7 @@ private void onVersionChanged(Integer previousVersionCode, Integer currentVersio
AppRelease appRelease = AppReleaseManager.storeAppReleaseAndReturnDiff(currentAppRelease);
if (appRelease != null) {
ApptentiveLog.d("App release was updated.");
database.addPayload(appRelease);
taskManager.addPayload(appRelease);
}
invalidateCaches();
}
Expand Down Expand Up @@ -840,7 +851,7 @@ void syncDevice() {
if (deviceInfo != null) {
ApptentiveLog.d("Device info was updated.");
ApptentiveLog.v(deviceInfo.toString());
database.addPayload(deviceInfo);
taskManager.addPayload(deviceInfo);
} else {
ApptentiveLog.d("Device info was not updated.");
}
Expand All @@ -854,7 +865,7 @@ private void syncSdk() {
if (sdk != null) {
ApptentiveLog.d("Sdk was updated.");
ApptentiveLog.v(sdk.toString());
database.addPayload(sdk);
taskManager.addPayload(sdk);
} else {
ApptentiveLog.d("Sdk was not updated.");
}
Expand All @@ -868,7 +879,7 @@ private void syncPerson() {
if (person != null) {
ApptentiveLog.d("Person was updated.");
ApptentiveLog.v(person.toString());
database.addPayload(person);
taskManager.addPayload(person);
} else {
ApptentiveLog.d("Person was not updated.");
}
Expand Down Expand Up @@ -971,6 +982,13 @@ static String getApptentivePushNotificationData(Bundle pushBundle) {
return null;
}

static String getApptentivePushNotificationData(Map<String, String> pushData) {
if (pushData != null) {
return pushData.get(APPTENTIVE_PUSH_EXTRA_KEY);
}
return null;
}

boolean setPendingPushNotification(String apptentivePushData) {
if (apptentivePushData != null) {
ApptentiveLog.d("Saving Apptentive push notification data.");
Expand Down Expand Up @@ -1056,7 +1074,7 @@ private void setPersonId(String newPersonId) {

public void resetSdkState() {
prefs.edit().clear().apply();
database.reset(appContext);
taskManager.reset(appContext);
}

public void notifyInteractionUpdated(boolean successful) {
Expand Down
Loading

0 comments on commit dda74f8

Please sign in to comment.