/*
* Copyright (c) 2012 Socialize Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.socialize.notifications;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.util.Log;
import com.socialize.android.ioc.IBeanFactory;
import com.socialize.android.ioc.Logger;
import com.socialize.api.DeviceRegistrationSystem;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.user.UserSystem;
import com.socialize.config.SocializeConfig;
import com.socialize.entity.DeviceRegistration;
import com.socialize.entity.User;
import com.socialize.error.SocializeException;
import com.socialize.log.SocializeLogger;
import com.socialize.util.StringUtils;
import java.util.List;
/**
* @author Jason Polites
*/
public class SocializeNotificationRegistrationSystem implements NotificationRegistrationSystem {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
private SocializeConfig config;
private SocializeLogger logger;
private DeviceRegistrationSystem deviceRegistrationSystem;
private UserSystem userSystem;
private IBeanFactory<DeviceRegistration> deviceRegistrationFactory;
private NotificationRegistrationState notificationRegistrationState;
@Override
public boolean isRegistrationPending() {
return notificationRegistrationState.isC2dmPending();
}
@Override
public boolean isRegisteredC2DM(Context context) {
return notificationRegistrationState.isRegisteredC2DM(context);
}
@Override
public boolean isSocializeRegistrationPending() {
return notificationRegistrationState.isSocializeRegistrationPending();
}
@Override
public boolean isRegisteredSocialize(Context context, User user) {
return notificationRegistrationState.isRegisteredSocialize(context, user);
}
@Override
public void registerC2DMFailed(Context context, String cause) {
notificationRegistrationState.setC2dmPendingRequestTime(0);
}
@Override
public void registerC2DMAsync(final Context context) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
registerC2DM(context);
}
catch (Exception e) {
if(logger != null) {
logger.error("Error during smart alert registration", e);
}
else {
Log.e(Logger.LOG_KEY, "Error during smart alert registration", e);
}
}
return null;
}
}.execute();
}
@Override
public synchronized void registerC2DM(final Context context) {
if(!isRegisteredC2DM(context) && !notificationRegistrationState.isC2dmPending() && config.getBooleanProperty(SocializeConfig.GCM_REGISTRATION_ENABLED, true)) {
if(logger != null && logger.isDebugEnabled()) {
logger.debug("Registering with GCM");
}
notificationRegistrationState.setC2dmPendingRequestTime(System.currentTimeMillis());
@SuppressWarnings("deprecation")
String senderId = config.getProperty(SocializeConfig.SOCIALIZE_GCM_SENDER_ID, config.getProperty(SocializeConfig.SOCIALIZE_C2DM_SENDER_ID));
String customSender = config.getProperty(SocializeConfig.SOCIALIZE_CUSTOM_GCM_SENDER_ID);
// Only supported in GCM
if(!StringUtils.isEmpty(senderId) && !StringUtils.isEmpty(customSender) && !senderId.equals(customSender)) {
senderId = senderId + "," + customSender;
}
Intent implicitIntent = newIntent(REQUEST_REGISTRATION_INTENT);
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentServices(implicitIntent, 0);
if (resolveInfos != null
&& resolveInfos.size() > 1) {
ResolveInfo serviceInfo = resolveInfos.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
Intent registrationIntent = newIntent(implicitIntent);
registrationIntent.setComponent(component);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, newPendingIntent(context));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
}
}
else {
if(logger != null && logger.isDebugEnabled()) {
logger.debug("GCM registration already in progress, complete or disabled");
}
}
}
@Override
public void registerSocialize(final Context context, final String registrationId) {
notificationRegistrationState.setPendingSocializeRequestTime(System.currentTimeMillis());
notificationRegistrationState.save(context);
if(!StringUtils.isEmpty(registrationId)) {
try {
// This should be synchronous. We don't want to launch an async task off the main UI thread.
SocializeSession session = userSystem.authenticateSynchronous(context, config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_KEY), config.getProperty(SocializeConfig.SOCIALIZE_CONSUMER_SECRET));
doRegistrationSocialize(context, session, registrationId);
}
catch (SocializeException e) {
logError(e);
}
}
}
protected void doRegistrationSocialize(final Context context, final SocializeSession session, final String registrationId) {
// Record the registration with Socialize
DeviceRegistration registration = deviceRegistrationFactory.getBean();
registration.setRegistrationId(registrationId);
try {
deviceRegistrationSystem.registerDeviceSynchronous(session, registration);
notificationRegistrationState.setC2DMRegistrationId(registrationId);
notificationRegistrationState.setRegisteredSocialize(session.getUser());
notificationRegistrationState.save(context);
if(logger != null && logger.isInfoEnabled()) {
logger.info("Registration with Socialize for GCM successful.");
}
}
catch (SocializeException e) {
if(logger != null) {
logger.error("Error registering device with Socialize. Will retry on next start", e);
}
}
}
protected void logError(Exception e) {
if(logger != null) {
logger.error("Error during device registration", e);
}
else {
SocializeLogger.e(e.getMessage(), e);
}
}
// So we can mock
protected Intent newIntent(String action) {
return new Intent(action);
}
protected Intent newIntent(Intent intent) {
return new Intent(intent);
}
// So we can mock
protected PendingIntent newPendingIntent(Context context) {
return PendingIntent.getBroadcast(context, 0, new Intent(), 0);
}
public void setConfig(SocializeConfig config) {
this.config = config;
}
public void setLogger(SocializeLogger logger) {
this.logger = logger;
}
public void setDeviceRegistrationSystem(DeviceRegistrationSystem deviceRegistrationSystem) {
this.deviceRegistrationSystem = deviceRegistrationSystem;
}
public void setNotificationRegistrationState(NotificationRegistrationState notificationRegistrationState) {
this.notificationRegistrationState = notificationRegistrationState;
}
public void setDeviceRegistrationFactory(IBeanFactory<DeviceRegistration> deviceRegistrationFactory) {
this.deviceRegistrationFactory = deviceRegistrationFactory;
}
public void setUserSystem(UserSystem userSystem) {
this.userSystem = userSystem;
}
}