/*******************************************************************************
* Software Name : RCS IMS Stack
*
* Copyright (C) 2010 France Telecom S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.orangelabs.rcs.service;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.accounts.Account;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.XmlResourceParser;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import com.orangelabs.rcs.R;
import com.orangelabs.rcs.addressbook.AccountChangedReceiver;
import com.orangelabs.rcs.addressbook.AuthenticationService;
import com.orangelabs.rcs.platform.AndroidFactory;
import com.orangelabs.rcs.platform.registry.AndroidRegistryFactory;
import com.orangelabs.rcs.provider.BackupRestoreDb;
import com.orangelabs.rcs.provider.eab.ContactsManager;
import com.orangelabs.rcs.provider.settings.RcsSettings;
import com.orangelabs.rcs.provider.settings.RcsSettingsData;
import com.orangelabs.rcs.provisioning.ProvisioningInfo;
import com.orangelabs.rcs.provisioning.https.HttpsProvisioningService;
import com.orangelabs.rcs.service.api.client.ClientApiIntents;
import com.orangelabs.rcs.utils.logger.Logger;
/**
* RCS start service.
*
* @author hlxn7157
*/
public class StartService extends Service {
/**
* RCS new user account
*/
public static final String REGISTRY_NEW_USER_ACCOUNT = "NewUserAccount";
/**
* Connection manager
*/
private ConnectivityManager connMgr = null;
/**
* Network state listener
*/
private BroadcastReceiver networkStateListener = null;
/**
* Last User account
*/
private String lastUserAccount = null;
/**
* Current User account
*/
private String currentUserAccount = null;
/**
* Launch boot flag
*/
boolean boot = false;
/**
* Launch user flag
*/
boolean user = false;
/**
* The logger
*/
private static Logger logger = Logger.getLogger(StartService.class.getSimpleName());
private static final String INTENT_KEY_BOOT = "boot";
private static final String INTENT_KEY_USER = "user";
@Override
public void onCreate() {
// Instantiate RcsSettings
RcsSettings.createInstance(getApplicationContext());
int autoConfigMode = RcsSettings.getInstance().getAutoConfigMode();
if (logger.isActivated()) {
logger.debug("onCreate AutoConfigMode="+autoConfigMode);
}
// In manual configuration, use a network listener to start RCS core when the data will be ON
if (autoConfigMode == RcsSettingsData.NO_AUTO_CONFIG) {
registerNetworkStateListener();
}
}
@Override
public void onDestroy() {
// Unregister network state listener
if (networkStateListener != null) {
try {
unregisterReceiver(networkStateListener);
} catch (IllegalArgumentException e) {
// Nothing to do
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if (logger.isActivated()) {
logger.debug("Start RCS service");
}
new Thread() {
@Override
public void run() {
// Check boot
if (intent != null) {
boot = intent.getBooleanExtra(INTENT_KEY_BOOT, false);
user = intent.getBooleanExtra(INTENT_KEY_USER, false);
}
if (checkAccount()) {
launchRcsService(boot, user);
} else {
// User account can't be initialized (no radio to read IMSI, .etc)
if (logger.isActivated()) {
logger.error("Can't create the user account");
}
// Send service intent
Intent stopIntent = new Intent(ClientApiIntents.SERVICE_STATUS);
stopIntent.putExtra("status", ClientApiIntents.SERVICE_STATUS_STOPPED);
sendBroadcast(stopIntent);
// Exit service
stopSelf();
}
}
}.start();
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Register a broadcast receiver for network state changes
*/
private void registerNetworkStateListener() {
// Get connectivity manager
if (connMgr == null) {
connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
}
// Instantiate the network listener
networkStateListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, final Intent intent) {
new Thread() {
public void run() {
connectionEvent(intent.getAction());
}
}.start();
}
};
// Register network state listener
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkStateListener, intentFilter);
}
/**
* Connection event
*
* @param action Connectivity action
*/
private void connectionEvent(String action) {
if (logger.isActivated()) {
logger.debug("Connection event " + action);
}
// Try to start the service only if a data connectivity is available
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if ((networkInfo != null) && networkInfo.isConnected()) {
if (logger.isActivated()) {
logger.debug("Device connected - Launch RCS service");
}
// Start the RCS core service
LauncherUtils.launchRcsCoreService(getApplicationContext());
// Stop Network listener
if (networkStateListener != null) {
try {
unregisterReceiver(networkStateListener);
} catch (IllegalArgumentException e) {
// Nothing to do
}
networkStateListener = null;
}
}
}
}
/**
* Set the country code
*
* @return Boolean
*/
private boolean setCountryCode() {
// Get country code
TelephonyManager mgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String countryCodeIso = mgr.getSimCountryIso();
if (countryCodeIso == null) {
if (logger.isActivated()) {
logger.error("Can't read country code from SIM");
}
return false;
}
// Parse country table to resolve the area code and country code
try {
XmlResourceParser parser = getResources().getXml(R.xml.country_table);
parser.next();
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("Data")) {
if (parser.getAttributeValue(null, "code").equalsIgnoreCase(countryCodeIso)) {
String countryCode = parser.getAttributeValue(null, "cc");
String areaCode = parser.getAttributeValue(null, "tc");
if (countryCode != null) {
if (!countryCode.startsWith("+")) {
countryCode = "+" + countryCode;
}
if (logger.isActivated()) {
logger.info("Set country code to " + countryCode);
}
RcsSettings.getInstance().setCountryCode(countryCode);
if (logger.isActivated()) {
logger.info("Set area code to " + areaCode);
}
RcsSettings.getInstance().setCountryAreaCode(areaCode);
return true;
}
}
}
}
eventType = parser.next();
}
if (logger.isActivated()) {
logger.error("Country code not found");
}
return false;
} catch (XmlPullParserException e) {
if (logger.isActivated()) {
logger.error("Can't parse country code from XML file", e);
}
return false;
} catch (IOException e) {
if (logger.isActivated()) {
logger.error("Can't read country code from XML file", e);
}
return false;
}
}
/**
* Check account
*
* @return true if an account is available
*/
private boolean checkAccount() {
AndroidFactory.setApplicationContext(getApplicationContext());
// Read the current and last end user account
currentUserAccount = LauncherUtils.getCurrentUserAccount(getApplicationContext());
lastUserAccount = LauncherUtils.getLastUserAccount(getApplicationContext());
if (logger.isActivated()) {
logger.info("Last user account is " + lastUserAccount);
logger.info("Current user account is " + currentUserAccount);
}
// Check the current SIM
if (currentUserAccount == null) {
if (isFirstLaunch()) {
// If it's a first launch the IMSI is necessary to initialize the service the first time
return false;
} else {
// Set the user account ID from the last used IMSI
currentUserAccount = lastUserAccount;
}
}
// On the first launch and if SIM card has changed
if (isFirstLaunch()) {
// Set the country code
boolean result = setCountryCode();
if (!result) {
// Can't set the country code
return false;
}
// Set new user flag
setNewUserAccount(true);
} else
if (hasChangedAccount()) {
// keep a maximum of saved accounts
BackupRestoreDb.cleanBackups(currentUserAccount);
// Backup last account settings
if (lastUserAccount != null) {
if (logger.isActivated()) {
logger.info("Backup " + lastUserAccount);
}
BackupRestoreDb.backupAccount(lastUserAccount);
}
// Set the country code
boolean result = setCountryCode();
if (!result) {
// Can't set the country code
return false;
}
// Reset RCS account
LauncherUtils.resetRcsConfig(getApplicationContext());
// Restore current account settings
if (logger.isActivated()) {
logger.info("Restore " + currentUserAccount);
}
BackupRestoreDb.restoreAccount(currentUserAccount);
// Activate service if new account
RcsSettings.getInstance().setServiceActivationState(true);
// Set new user flag
setNewUserAccount(true);
} else {
// Set new user flag
setNewUserAccount(false);
}
// Check if the RCS account exists
Account account = AuthenticationService.getAccount(getApplicationContext(),
getString(R.string.rcs_core_account_username));
if (account == null) {
// No account exists
if (logger.isActivated()) {
logger.debug("The RCS account does not exist");
}
if (AccountChangedReceiver.isAccountResetByEndUser()) {
// It was manually destroyed by the user
if (logger.isActivated()) {
logger.debug("It was manually destroyed by the user, we do not recreate it");
}
return false;
} else {
if (logger.isActivated()) {
logger.debug("Recreate a new RCS account");
}
AuthenticationService.createRcsAccount(getApplicationContext(),
getString(R.string.rcs_core_account_username), true);
}
} else {
// Account exists: checks if it has changed
if (hasChangedAccount()) {
// Account has changed (i.e. new SIM card): delete the current account and create a new one
if (logger.isActivated()) {
logger.debug("Deleting the old RCS account for " + lastUserAccount);
}
ContactsManager.createInstance(getApplicationContext());
ContactsManager.getInstance().deleteRCSEntries();
AuthenticationService.removeRcsAccount(getApplicationContext(), null);
if (logger.isActivated()) {
logger.debug("Creating a new RCS account for " + currentUserAccount);
}
AuthenticationService.createRcsAccount(getApplicationContext(),
getString(R.string.rcs_core_account_username), true);
}
}
// Save the current end user account
LauncherUtils.setLastUserAccount(getApplicationContext(), currentUserAccount);
return true;
}
/**
* Launch the RCS service.
*
* @param boot indicates if RCS is launched from the device boot
* @param user indicates if RCS is launched from the user interface
*/
private void launchRcsService(boolean boot, boolean user) {
int mode = RcsSettings.getInstance().getAutoConfigMode();
if (logger.isActivated())
logger.debug("Launch RCS service: HTTPS=" + (mode == RcsSettingsData.HTTPS_AUTO_CONFIG) + ", boot=" + boot + ", user=" + user);
if (mode == RcsSettingsData.HTTPS_AUTO_CONFIG) {
// HTTPS auto config
String version = RcsSettings.getInstance().getProvisioningVersion();
// Check the last provisioning version
if (ProvisioningInfo.Version.RESETED_NOQUERY.equals(version)) {
// (-1) : RCS service is permanently disabled. SIM change is required
if (hasChangedAccount()) {
// Start provisioning as a first launch
HttpsProvisioningService.startHttpsProvisioningService(getApplicationContext(), true, user, boot);
} else {
if (logger.isActivated()) {
logger.debug("Provisioning is blocked with this account");
}
}
} else {
if (isFirstLaunch() || hasChangedAccount()) {
// First launch: start the auto config service with special tag
HttpsProvisioningService.startHttpsProvisioningService(getApplicationContext(), true, user, boot);
} else {
if (ProvisioningInfo.Version.DISABLED_NOQUERY.equals(version)) {
// -2 : RCS client and configuration query is disabled
if (user) {
// Only start query if requested by user action
HttpsProvisioningService.startHttpsProvisioningService(getApplicationContext(), false, user, boot);
}
} else {
// Start or restart the HTTP provisioning service
HttpsProvisioningService.startHttpsProvisioningService(getApplicationContext(), false, user, boot);
if (ProvisioningInfo.Version.DISABLED_DORMANT.equals(version)) {
// -3 : RCS client is disabled but configuration query is not
} else {
// Start the RCS core service
LauncherUtils.launchRcsCoreService(getApplicationContext());
}
}
}
}
} else {
// No auto config: directly start the RCS core service
LauncherUtils.launchRcsCoreService(getApplicationContext());
}
}
/**
* Is the first RCs is launched ?
*
* @return true if it's the first time RCS is launched
*/
private boolean isFirstLaunch() {
return (lastUserAccount == null);
}
/**
* Check if RCS account has changed since the last time we started the service
*
* @return true if the active account was changed
*/
private boolean hasChangedAccount() {
if (lastUserAccount == null) {
return true;
} else
if (currentUserAccount == null) {
return false;
} else {
return (!currentUserAccount.equalsIgnoreCase(lastUserAccount));
}
}
/**
* Set true if new user account
*
* @param value true if new user account
*/
private void setNewUserAccount(boolean value) {
SharedPreferences preferences = getSharedPreferences(AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(REGISTRY_NEW_USER_ACCOUNT, value);
editor.commit();
}
/**
* Check if new user account
*
* @param context Application context
* @return true if new user account
*/
public static boolean getNewUserAccount(Context context) {
SharedPreferences preferences = context.getSharedPreferences(AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);
return preferences.getBoolean(REGISTRY_NEW_USER_ACCOUNT, false);
}
/**
* Launch the RCS start service
*
* @param context
* @param boot
* start RCS service upon boot
* @param user
* start RCS service upon user action
*/
static void LaunchRcsStartService(Context context, boolean boot, boolean user) {
if (logger.isActivated())
logger.debug("Launch RCS service (boot=" + boot + ") (user="+user+")");
Intent intent = new Intent(context, StartService.class);
intent.putExtra(INTENT_KEY_BOOT, boot);
intent.putExtra(INTENT_KEY_USER, user);
context.startService(intent);
}
}